home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dskut / tdsk21sr.zip / TDSK.ASM < prev   
Assembly Source File  |  1993-01-31  |  135KB  |  3,138 lines

  1.  
  2. ;┌───────────────────────────────────────────────────────────────────┐
  3. ;│                                                                   │
  4. ;│ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▄ │
  5. ;│  ▀▀▒▒█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ │
  6. ;│    ▒▒█  ▒▒▄ ▒▒▄  ▒▒▒▒▄   ▒▒▒▒▄     ▒▒▄   ▒▒▒▒▄   ▒▒▒▒▒▒▄ ▒▒▄  ▒▒▄ │
  7. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█▀▒▒▄ ▒▒█▀▒▒▄ ▒▒▄▀▒▒▄ ▒▒█▀▒▒▄ ▒▒█▀▀▀▀ ▒▒█ ▒▒█▀ │
  8. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█     ▒▒█▒▒█▀  │
  9. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒▒▒▄▀▀ ▒▒▒▒▄▀▀ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒▒▒▒▒▄ ▒▒▒▒█▀   │
  10. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█▀▒▒▄ ▒▒█▀▒▒▄ ▒▒█ ▒▒█ ▒▒█ ▒▒█  ▀▀▀▒▒█ ▒▒█▒▒▄   │
  11. ;│    ▒▒█  ▒▒█ ▒▒█  ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒█ ▒▒▄ ▒▒█ ▒▒█ ▒▒▄  │
  12. ;│    ▒▒█  ▒▒▒▒▒▒▒▄ ▒▒█ ▒▒█ ▒▒▒▒▄▀▀  ▀▒▒▄▀▀ ▒▒▒▒▒█▀ ▒▒▒▒▒▒█ ▒▒█  ▒▒▄ │
  13. ;│     ▀▀   ▀▀▀▀▀▀▀  ▀▀  ▀▀  ▀▀▀▀      ▀▀    ▀▀▀▀▀   ▀▀▀▀▀▀  ▀▀   ▀▀ │
  14. ;│                                                                   │
  15. ;│           ░░▒▒▓▓██▓▓▒▒░░   Versión 2.1   ░░▒▒▓▓██▓▓▒▒░░           │
  16. ;│                                                                   │
  17. ;│                                                                   │
  18. ;│     CONTROLADOR DE DISCO VIRTUAL PARA SISTEMAS DOS Y WINDOWS 3    │
  19. ;│                                                                   │
  20. ;│              * * * Programa de Dominio Público * * *              │
  21. ;│                                                                   │
  22. ;│              (c) Enero 1993  Ciriaco García de Celis.             │
  23. ;│     Grupo Universitario de Informática. Facultad de Ciencias.     │
  24. ;│                Apartado 6062 - Valladolid (España)                │
  25. ;│                                                                   │
  26. ;│                        Mail (Internet):                           │
  27. ;│                                gui@cpd.uva.es                     │
  28. ;│                                amiga@hp9000.uva.es                │
  29. ;│                        (Subject: "Mensaje para 040")              │
  30. ;│                                                                   │
  31. ;└───────────────────────────────────────────────────────────────────┘
  32.  
  33.    ;   Aviso:   Este programa contiene instrucciones exclusivas de los
  34.    ;          procesadores 386 y superiores.  Debe ser ensamblado como
  35.    ;          fichero  EXE,  de la siguiente manera,  para asegurar la
  36.    ;          compatibilidad con los procesadores 8086 y 286:
  37.    ;
  38.    ;          - Con TASM 2.0:
  39.    ;                            TASM tdsk /m3
  40.    ;                            TLINK tdsk
  41.    ;
  42.    ;          - Con MASM 6.0  (versiones anteriores de MASM generarían
  43.    ;            un disco virtual que requeriría  un  386  o  superior,
  44.    ;            además habría que mover las directivas  que  controlan
  45.    ;            el tipo de procesador y colocarlas con «peligro»):
  46.    ;
  47.    ;                            ML /Zm tdsk.asm
  48.    ;
  49.    ;                o alternativamente:
  50.    ;
  51.    ;                            ML /c /Zm tdsk.asm
  52.    ;                            TLINK tdsk
  53.    ;
  54.    ;               La ventaja de TLINK frente a LINK es que el fichero
  55.    ;            ejecutable ocupa  2 Kbytes  menos en disco (a la tabla
  56.    ;            ubicada al final del programa  se  le  asigna  memoria
  57.    ;            en la cabecera del fichero EXE y no ocupando disco).
  58.    ;
  59.    ;   IMPORTANTE:  Cualquier cambio realizado en el programa debe ser
  60.    ;                documentado,  indicando claramente en el listado y
  61.    ;                en el fichero DOC quién lo ha realizado.
  62.  
  63.  
  64. ; ------------ Macros de propósito general
  65.  
  66. XPUSH          MACRO regmem            ; apilar lista de registros
  67.                  IRP rm, <regmem>
  68.                    PUSH rm
  69.                  ENDM
  70.                ENDM
  71.  
  72. XPOP           MACRO regmem            ; desapilar lista de registros
  73.                  IRP rm, <regmem>
  74.                    POP rm
  75.                  ENDM
  76.                ENDM
  77.  
  78. ; ------------ Estructuras de datos
  79.  
  80. cab_PETICION   STRUC                   ; parte inicial común a todos
  81. tamano         DB    ?                 ; los comandos de la cabecera
  82. unidad         DB    ?                 ; de petición
  83. orden          DB    ?
  84. estado         DW    ?
  85. dos_info       DB    8 DUP (?)
  86. cab_PETICION   ENDS
  87.  
  88. cab_INIT_BBPB  STRUC                   ; para comandos INIT/BUILD_BPB
  89.                DB    (TYPE cab_PETICION) DUP (?)
  90. num_discos     DB    ?                 ; número de unidades definidas
  91. fin_resid_desp DW    ?                 ; área que quedará residente
  92. fin_resid_segm DW    ?
  93. bpb_cmd_desp   DW    ?                 ; línea de órdenes del CONFIG
  94. bpb_cmd_segm   DW    ?                 ; y puntero al BPB
  95. nuevo_disco    DB    ?                 ; (DOS 3+) (0-A:, 1-B:,...)
  96. cab_INIT_BBPB  ENDS
  97.  
  98. cab_MEDIACHECK STRUC                   ; estructura para MEDIA CHECK
  99.                DB    (TYPE cab_PETICION) DUP (?)
  100. media_descrip  DB    ?                 ; descriptor de medio
  101. cambio         DB    ?                 ; 1: no cambiado, 0FFh:sí, 0:?
  102. cab_MEDIACHECK ENDS
  103.  
  104. cab_READ_WRITE STRUC
  105.                DB    (TYPE cab_PETICION) DUP (?)
  106.                DB    ?                 ; descriptor de medio
  107. transfer_desp  DW    ?                 ; dirección de transferencia
  108. transfer_segm  DW    ?
  109. transfer_sect  DW    ?                 ; nº de sectores a transferir
  110. transfer_sini  DW    ?                 ; primer sector a transferir
  111. cab_READ_WRITE ENDS
  112.  
  113.  
  114. ; ************ Disco virtual: inicio del área residente.
  115.  
  116. _PRINCIPAL     SEGMENT
  117.                ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
  118.  
  119.                DD    -1           ; encadenamiento con otros drivers
  120. tipo_drive     DW    0800h        ; palabra de atributo:
  121.                                   ; bit 15 a 0: dispositivo de bloques
  122.                                   ; bit 14 a 0: sin control IOCTL
  123.                                   ; bit 13 a 0: formato IBM
  124.                                   ; bit 11 a 1: soportados Open/Close
  125.                                   ;             y Remove (DOS 3.0+)
  126.                DW    estrategia   ; rutina de estrategia
  127.                DW    interrupcion ; rutina de interrupción
  128.                DB    1            ; número de unidades
  129.  
  130. ; ------------ Variables y tablas de datos globales fijas. Estas
  131. ;              variables no serán movidas de sitio en otras versiones
  132. ;              de TURBODSK, con objeto de facilitar un control externo
  133. ;              del disco virtual por parte de otros programas. Todo lo
  134. ;              que está dentro del «área a actualizar» será copiado
  135. ;              sobre el TURBODSK residente al redefinir el disco, para
  136. ;              inicializar todas las variables precisas.
  137.  
  138. cs_tdsk        DW    ? ; Segmento de TDSK. Con QEMM-386, los drivers
  139.                        ; pueden ser relocalizados en memoria superior
  140.                        ; de tal manera que parte de la cabecera queda
  141.                        ; en memoria convencional, con el dispositivo
  142.                        ; completo en la memoria superior, en la que es
  143.                        ; ejecutado. Tras la instalación, QEMM copia en
  144.                        ; memoria convencional los primeros 18 bytes de
  145.                        ; la cabecera, entre los que está esta palabra,
  146.                        ; actualizándola. Pese a que la cadena de
  147.                        ; dispositivos del sistema pasa por la memoria
  148.                        ; convencional en este caso, esta variable nos
  149.                        ; permite conocer la dirección REAL en memoria
  150.                        ; superior (o en cualquier otra) de TURBODSK,
  151.                        ; que así es compatible con el LOADHI de QEMM.
  152.  
  153. id_tdsk        DB    "TDS21" ; esto es TURBODSK 2.1 y no otro
  154.                              ; controlador de dispositivo
  155.  
  156. num_ordenes    DB    10h     ; nº de órdenes soportadas
  157.  
  158. i_tdsk_ctrl    EQU   $       ; inicio del área a actualizar
  159.  
  160. tipo_soporte   DB    0FFh    ; 0: disco no formateado
  161.                              ; 1: se emplea memoria XMS 2.0+
  162.                              ; 2:  "    "     "     EMS 3.2+
  163.                              ; 3:  "    "     " convencional
  164.                              ; 0FFh: aún no ejecutada INIT
  165.  
  166. cambiado       DB    ?       ; al formatear el disco virtual se pone
  167.                              ; a 0FFh (para indicar cambio de disco)
  168.  
  169. mem_handle     DW    ?       ; para memoria EMS/XMS; si se utiliza
  170.                              ; memoria convencional, apunta al
  171.                              ; segmento donde empieza el disco
  172.  
  173. tdsk_psp       DW    ?       ; segmento del PSP residente si se
  174.                              ; utiliza memoria convencional
  175.  
  176. ems_pagina0    DW    ?       ; segmento de página EMS (si se emplea)
  177. ems_paginai    DW    ?       ; segmento alternativo
  178. ems_pagni      DB    ?       ; nº de página física alternativa
  179.  
  180. xms_driver     LABEL DWORD   ; dirección del controlador XMS, en el
  181. xms_desp       DW    ?       ; caso de emplear memoria XMS.
  182. xms_segm       DW    ?
  183.  
  184. cpu386         DB    OFF     ; a ON si 386 ó superior
  185.  
  186. f_tdsk_ctrl    EQU   $       ; final del área a actualizar
  187.  
  188. letra_unidad   DB    ?       ; letra ASCII del disco ('C', 'D',...)
  189.  
  190. bpb_ptr        DW    bpb     ; puntero al BPB del disco
  191.  
  192. rutina_larga   DB    OFF     ; a ON si reservado espacio en
  193.                              ; memoria para la larga rutina de
  194.                              ; gestión de memoria EMS.
  195.  
  196. ; ------------ Variables internas de TURBODSK; su ubicación podría
  197. ;              cambiar en futuras versiones del programa.
  198.  
  199. pcab_peticion  LABEL DWORD        ; puntero a la cabecera de petición
  200. pcab_pet_desp  DW    0
  201. pcab_pet_segm  DW    0
  202.  
  203. p_rutinas      LABEL WORD         ; tabla de rutinas del controlador
  204.                DW    init
  205.                DW    media_check
  206.                DW    build_bpb
  207.                DW    ioctl_input
  208.                DW    read
  209.                DW    read_nowait
  210.                DW    input_status
  211.                DW    input_flush
  212.                DW    write
  213.                DW    write_verify
  214.                DW    output_status
  215.                DW    output_flush
  216.                DW    ioctl_output
  217.                DW    open              ; DOS 3.0+
  218.                DW    close             ; DOS 3.0+
  219.                DW    remove            ; DOS 3.0+
  220.  
  221. media          EQU   0FAh    ; byte descriptor de medio utilizado por
  222.                              ; TURBODSK. No es 0F8h como en los discos
  223.                              ; virtuales del sistema ya que TURBODSK
  224.                              ; no es un dispositivo fijo. Este byte no
  225.                              ; es empleado por los discos estándar del
  226.                              ; dos y al ser mayor de 0F7h no provoca
  227.                              ; mensajes extraños con antiguos CHKDSKs.
  228.  
  229. bpb            LABEL BYTE    ; Estos valores del BPB son arbitrarios:
  230. bytes_sector   DW    512     ; se inicializarán si se define el disco
  231. sect_cluster   DB    1       ; al instalar desde el CONFIG; en caso
  232. sect_reserv    DW    1       ; contrario, como son correctos, el DOS
  233. num_fats       DB    1       ; no tendrá problemas para realizar sus
  234. entradas_raiz  DW    128     ; cálculos internos iniciales al instalar
  235. num_sect       DW    128     ; el driver. En concreto, el tamaño de
  236. media_byte     DB    media   ; sector influye de manera directa en el
  237. sectores_fat   DW    4       ; tamaño de los buffers de disco del DOS.
  238. fin_bpb        EQU   $
  239.  
  240. ; ------------ Rutina de estrategia del disco virtual.
  241.  
  242. estrategia     PROC  FAR
  243.                MOV   CS:pcab_pet_desp,BX
  244.                MOV   CS:pcab_pet_segm,ES
  245.                RET
  246. estrategia     ENDP
  247.  
  248. ; ------------ Rutina de interrupción del disco virtual. TURBODSK,
  249. ;              al igual que RAMDRIVE o VDISK, no define una pila
  250. ;              interna. Es responsabilidad del DOS que ésta tenga el
  251. ;              tamaño adecuado (con el disco en memoria XMS, el
  252. ;              controlador XMS puede requerir hasta 256 bytes de
  253. ;              pila). TURBODSK no consume más de 64 bytes de pila en
  254. ;              ningún momento, y sólo alrededor de 48 antes de llamar
  255. ;              al controlador XMS cuando se emplea esta memoria.
  256.  
  257. interrupcion   PROC  FAR
  258.                XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
  259.                LDS   BX,CS:pcab_peticion
  260.                MOV   AL,[BX].orden     ; AL = orden
  261.                MOV   AH,0              ; AX = orden
  262.                CMP   AL,CS:num_ordenes
  263.                JB    orden_ok          ; orden soportada
  264.                MOV   AL,3              ;   " desconocida (IOCTL INPUT)
  265. orden_ok:      CMP   CS:tipo_soporte,AH
  266.                JNE   no_test_fmt       ; tipo_soporte distinto de 0
  267.                MOV   AX,8102h          ; disco no formateado: error
  268.                JMP   exit_interr
  269. no_test_fmt:   SHL   AX,1              ; orden = orden * 2
  270.                MOV   SI,AX
  271.                XPUSH <BX,DS>
  272.                XOR   BP,BP
  273.                MOV   AX,100h
  274.                CALL  CS:[SI+OFFSET p_rutinas]  ; ejecutar orden
  275.                XPOP  <DS,BX>
  276.                AND   AH,AH
  277.                JNS   exit_interr          ; no hubo error (bit 15 = 0)
  278.                CMP   AL,3
  279.                JE    exit_interr          ; error de orden desconocida
  280.                MOV   [BX].transfer_sect,0 ; otro: movidos 0 sectores
  281. exit_interr:   MOV   [BX].estado,AX
  282.                XPOP  <ES,DS,BP,DI,SI,DX,CX,BX,AX>
  283.                RET
  284. interrupcion   ENDP
  285.  
  286. ; ------------ Las rutinas que controlan el dispositivo devuelven AX
  287. ;              con la palabra de estado. Pueden cambiar todos los
  288. ;              registros (de 16 bits), incluídos los de segmento. A la
  289. ;              entrada, BP=0 y AX=100h.
  290.  
  291. media_check:   MOV   AL,CS:cambiado    ; condición de «disco cambiado»
  292.                MOV   CS:cambiado,AH    ; de momento ya no cambiará más
  293.                MOV   [BX].cambio,AL
  294.  
  295. read_nowait:                           ; conjunto de órdenes con
  296. input_status:                          ; tratamiento idéntico
  297. input_flush:
  298. output_status:
  299. output_flush:
  300. ioctl_output:
  301. open:
  302. close:
  303. retorno_ok:    RET                     ; no hay error, ignorar orden
  304.  
  305. build_bpb:     MOV   [BX].bpb_cmd_desp,OFFSET bpb
  306.                MOV   [BX].bpb_cmd_segm,CS
  307.                JMP   retorno_ok
  308.  
  309. ioctl_input:   MOV   AX,8103h          ; orden no soportada
  310.                RET
  311.  
  312. remove:        MOV   AH,3              ; fin de función, indicar
  313.                RET                     ; «controlador ocupado»
  314.  
  315. nueva_int19    PROC                    ; Interceptar reinicialización
  316.                .286
  317.                PUSHA
  318.                XPUSH <DS,ES>           ; Esto es una interrupción
  319.                XOR   AX,AX
  320.                MOV   ES,AX
  321.                CMP   AL,CS:tipo_soporte ; ¿Disco formateado?
  322.                JE    no_lib             ; no
  323.                MOV   CS:tipo_soporte,AL ; sí: anularlo
  324.                CALL  procesa_io        ; CF=1: liberar memoria EMS/XMS
  325. no_lib:        LEA   SI,ant19off
  326.                MOV   DI,64h            ; desplazamiento de INT 19h
  327.                PUSH  CS
  328.                POP   DS
  329.                CLI
  330.                MOVSW
  331.                MOVSW
  332.                XPOP  <ES,DS>
  333.                POPA
  334.                DB    0EAh              ; código de JMP FAR SEG:OFF
  335. ant19off       DW    ?
  336. ant19seg       DW    ?
  337.                .8086
  338. nueva_int19    ENDP
  339.  
  340. read:          INC   BP                ; indicar lectura (BP=1)
  341. write:                                 ; escritura (BP=0)
  342. write_verify:
  343.  
  344. init_io        PROC                        ; preparar registros E/S
  345.                LES   DI,DWORD PTR [BX].transfer_desp  ; * direc. ES:DI
  346.                LDS   AX,DWORD PTR [BX].transfer_sect  ; nº sectores AX
  347.                MOV   BX,DS                 ; 1º sector ¡DS indefinido!
  348. io_proc:       MOV   SI,CS:bytes_sector
  349.                ADD   AX,BX
  350.                JNC   io_ok?                ; último sector < 65536
  351. io_no_ok:      MOV   AX,8108h              ; «sector no encontrado»
  352.                RET
  353. io_ok?:        CMP   AX,CS:num_sect
  354.                JA    io_no_ok              ; sector final ¡fuera!
  355.                SUB   AX,BX
  356.                MUL   SI                    ; DX(CF):AX = tamaño bloque
  357.                RCR   AX,1                  ; CF:AX/2 -> AX = palabras
  358.                MOV   CX,DI
  359.                NEG   CX                    ; 10000h-CX: CF=1 si CX<>0
  360.                CMC                         ; CF:CX bytes hasta fin de
  361.                RCR   CX,1                  ; segmento = (10000h-DI)/2
  362.                CMP   AX,CX
  363.                JAE   io_cx_ok
  364.                MOV   CX,AX                 ; * tamaño: CX palabras
  365. io_cx_ok:      JCXZ  io_no_ok              ; CX=0 si DI=0FFFFh (fatal)
  366.                MOV   AX,BX                 ; sector inicial
  367.                MUL   SI                    ; * desplazamiento en DX:AX
  368.                CLC                         ; ¡no reinicializando!
  369. init_io        ENDP
  370.  
  371. ; ------------ Area residente dependiente del tipo de memoria empleada
  372. ;              por el disco. La rutina instalada por defecto es la más
  373. ;              larga de todas, para «dejar hueco» donde copiar encima
  374. ;              las otras si se va a utilizar otro tipo de memoria. Si
  375. ;              se modifican las rutinas, convendría medirlas por si
  376. ;              acaso la de memoria EMS deja de ser la más larga...
  377.  
  378. procesa_io     EQU   $
  379.  
  380.                ; ---- La rutina de gestión de memoria EMS transfiere
  381.                ;      bloques de hasta 16Kb de una vez. Intenta mapear
  382.                ;      en la página física 0: si no puede, debido a un
  383.                ;      solapamiento con el buffer de transferencia del
  384.                ;      programa principal (si está también en memoria
  385.                ;      EMS), utiliza otra página alternativa que dista
  386.                ;      al menos 32 Kb absolutos de la 0. Para dilucidar
  387.                ;      si hay solapamiento, se compara la distancia
  388.                ;      entre direcciones origen y destino antes de la
  389.                ;      transferencia: si es mayor de 401h párrafos
  390.                ;      (16400 bytes, 16 para redondeo) no hay problema.
  391.                ;      Ante un solapamiento se procede a restaurar el
  392.                ;      contexto de las páginas mapeadas, antes y
  393.                ;      después de la transferencia, para poder acceder
  394.                ;      a la memoria expandida donde está el buffer del
  395.                ;      programa principal.
  396.  
  397. procesa_ems    PROC
  398.                JNC   no_emslib
  399.                MOV   DH,45h            ; sistema reinicializando:
  400.                CALL  llama_EMM         ; liberar memoria EMS
  401.                RET
  402. no_emslib:     MOV   SI,DX             ; preservar DX
  403.                MOV   DH,47h
  404.                CALL  llama_EMM         ; DH=47h -> salvar contexto EMS
  405.                MOV   DX,SI             ; recuperar DX
  406.                MOV   BX,4000h          ; tamaño de página (16 Kb)
  407.                DIV   BX                ; AX = 1ª página EMS a mapear
  408.                MOV   SI,DX             ; offset relativo en 1ª página
  409. procesa_pag:   PUSH  CX                ; **
  410.                MOV   BX,DI
  411.                MOV   CL,4
  412.                SHR   BX,CL             ; bytes del offset -> párrafos
  413.                MOV   CX,ES
  414.                ADD   BX,CX             ; AX = segmento de datos
  415.                MOV   CX,CS:ems_pagina0
  416.                MOV   DS,CX
  417.                XOR   DL,DL             ; intentar emplear página 0
  418.                SUB   BX,CX
  419.                JNC   rpos
  420.                NEG   BX                ; valor absoluto
  421. rpos:          CMP   BX,401h           ; distancia respecto página EMS
  422.                JAE   no_conflicto      ; más de 16 Kb: no solapamiento
  423.                CALL  copia_contexto    ; está CX apilado
  424.                MOV   DS,CS:ems_paginai
  425.                MOV   DL,CS:ems_pagni   ; usar página alternativa
  426.                OR    BP,8000h          ; indicar su uso
  427. no_conflicto:  POP   CX                ; * pila totalmente equilibrada
  428.                MOV   BX,AX
  429.                MOV   DH,44h            ; DL = 0 ó 2 (página física)
  430.                CALL  llama_EMM         ; DH = 44h -> mapear página EMS
  431.                XPUSH <CX,SI>           ; ++
  432.                SUB   SI,4000h
  433.                NEG   SI                ; SI = 4000h - SI: «resto»
  434.                SHR   SI,1              ; bytes -> palabras
  435.                CMP   CX,SI
  436.                JB    cx_ok             ; no ocupada toda la página
  437.                MOV   CX,SI
  438. cx_ok:         POP   SI                ; + SI=desplazamiento relativo
  439.                CLD
  440.                POP   BX                ; + palabras restantes
  441.                SUB   BX,CX             ; descontar las que se moverán
  442.                PUSH  BX                ; * volver a apilar el viejo CX
  443.                CALL  coloca_regs
  444.                CMP   CS:cpu386,ON      ; ¿386 o superior?
  445.                JNE   trans_16bit
  446.                .386
  447.                PUSHAD
  448.                SHR   CX,1              ; nº palabras de 32 bit a mover
  449.                JCXZ  transferido       ; evitar desgracia
  450.                XOR   EAX,EAX           ; asegurar no violación
  451.                DEC   AX                ; de segmento-64K
  452.                AND   ECX,EAX           ; EAX = 0FFFFh
  453.                AND   ESI,EAX
  454.                AND   EDI,EAX
  455.                REP   MOVSD             ; transferencia ultrarrápida
  456. transferido:   POPAD                   ; POPAD falla en muchos 386
  457.                .8086
  458.                NOP                     ; arreglar fallo de POPAD
  459.                ADD   CX,CX
  460.                ADD   DI,CX             ; simular cambio normal de DI
  461.                ADD   SI,CX             ; y de SI
  462.                JMP   fin_trans
  463. trans_16bit:   REP   MOVSW             ; mover palabras de 16 bit
  464. fin_trans:     CALL  coloca_regs
  465.                AND   BP,BP             ; ¿se usó página alternativa?
  466.                JNS   ahorra_ms
  467.                CALL  copia_contexto    ; está CX apilado
  468.                AND   BP,1              ; de momento, no se usará más
  469. ahorra_ms:     POP   CX                ; **
  470.                JCXZ  fin_leer          ; no quedan más palabras
  471.                INC   AX                ; próxima página EMS
  472.                XOR   SI,SI             ; ahora desde inicio página EMS
  473.                JMP   procesa_pag
  474. fin_leer:      MOV   DH,48h
  475.                CALL  llama_EMM         ; DH=47h restaurar contexto EMS
  476.                MOV   AX,100h           ; no hubo problemas
  477.                RET
  478. procesa_ems    ENDP
  479.  
  480.                ; ---- ¡Cuidado!: esta rutina debe ser invocada siempre
  481.                ;      con la pila (SP) tal y como estaba al principio
  482.                ;      del procedimiento «procesa_ems», y utilizando
  483.                ;      siempre CALL, para que en el caso de que haya
  484.                ;      errores retorne correctamente al nivel anterior
  485.                ;      (nivel previo a «procesa_ems»). Se corrompe DX
  486.                ;      y, si hay error, AX también (devuelve 810Ch).
  487.  
  488. llama_EMM      PROC
  489.                XPUSH <AX,BX,CX,BP>
  490.                MOV   AX,DX             ; función en AX
  491. llama_denuevo: MOV   DX,CS:mem_handle  ; handle EMS
  492.                XPUSH <AX,BX>
  493.                INT   67h               ; llamar al EMM
  494.                MOV   CL,AH
  495.                XPOP  <BX,AX>
  496.                AND   CL,CL
  497.                JZ    llama_ok          ; además, ZF = 1
  498.                CMP   CL,82h
  499.                JE    llama_denuevo     ; intentarlo hasta que funcione
  500. llama_ok:      XPOP  <BP,CX,BX,AX>
  501.                JNE   ret_atras
  502.                RET
  503. ret_atras:     POP   AX                ; sacar dirección de retorno
  504.                MOV   AX,810Ch          ; error de «anomalía general»
  505.                RET                     ; retornar dos niveles atrás
  506. llama_EMM      ENDP
  507.  
  508.                ; ---- ¡Cuidado!: esta rutina debe ser invocada siempre
  509.                ;      con CX (y sólo CX) apilado: recarga CX desde la
  510.                ;      pila y corrompe BX dejando aún en la pila CX.
  511.  
  512. copia_contexto PROC
  513.                XPOP  <BX,CX>           ; equilibrar pila a llama_EMM
  514.                MOV   DH,48h
  515.                CALL  llama_EMM         ; restaurar contexto EMS
  516.                MOV   DH,47h
  517.                CALL  llama_EMM         ; preservarlo de nuevo
  518.                PUSH  CX
  519.                JMP   BX                ; más rápido que PUSH BX/RET
  520. copia_contexto ENDP
  521.  
  522. coloca_regs    PROC                    ; ¿invertir sentido?
  523.                TEST  BP,1
  524.                JNZ   colocados
  525.                XCHG  SI,DI             ; escritura: invertir sentido
  526.                XPUSH <DS,ES>
  527.                XPOP  <DS,ES>
  528. colocados:     RET
  529. coloca_regs    ENDP
  530.  
  531. tam_proc_ems   EQU   $-OFFSET procesa_ems   ; tamaño de esta rutina
  532.  
  533.                ; <<< Fin del código residente del disco virtual >>>
  534.  
  535.  
  536. ; ************ Instalación (invocada desde CONFIG.SYS).
  537.  
  538. init           PROC
  539.                MOV   CS:modo,CONFIG         ; ejecutando desde CONFIG
  540.                CALL  obtDosVer              ; obtener versión del DOS
  541.                LEA   AX,retorno_ok
  542.                MOV   CS:p_rutinas,AX        ; anular rutina INIT
  543.                INC   CS:tipo_soporte        ; 0: disco no formateado
  544.                MOV   CS:cs_tdsk,CS          ; inicializar esa variable
  545.                CMP   CS:dosver,300h         ; ¿DOS inferior al 3.0?
  546.                JAE   dos_ok                 ; DOS 3.0+
  547.                AND   CS:tipo_drive,0F7FFh   ; ajustar atributos
  548.                MOV   CS:num_ordenes,0Dh     ; y número de órdenes
  549. dos_ok:        MOV   SI,[BX].bpb_cmd_desp
  550.                MOV   ES,[BX].bpb_cmd_segm   ; ES:SI -> parámetros
  551.                MOV   [BX].num_discos,1      ; una unidad de disco
  552.                LEA   AX,bpb_ptr
  553.                MOV   [BX].bpb_cmd_desp,AX
  554.                MOV   [BX].bpb_cmd_segm,CS   ; inicializado puntero BPB
  555.                CALL  desvia_int19           ; controlar INT 19h
  556.                CALL  inic_letra             ; obtener letra de unidad
  557.                MOV   BX,CS
  558.                MOV   DS,BX                  ; DS: -> _PRINCIPAL
  559.                MOV   BX,SI                  ; ES:BX -> parámetros
  560.                CALL  salta_nombre           ; buscar inicio parámetros
  561.                CALL  procesar_param         ; procesar parámetros
  562.                PUSH  DS                     ;
  563.                POP   ES                     ; ES: -> _PRINCIPAL
  564.                CMP   param_h,ON
  565.                JE    fin_instalar           ; piden ayuda
  566.                CALL  max_sector             ; obtener mayor sector
  567.                MOV   BX,param_tsect
  568.                CMP   BX,AX                  ; ¿el nuestro es mayor?
  569.                JBE   sect_def_ok            ; no
  570.                MOV   bytes_sector,BX        ; sí: ajustar BPB
  571. sect_def_ok:   CALL  errores_config
  572.                TEST  lista_err,ERROR0+ERROR1
  573.                JNZ   fin_instalar           ; algún error importante
  574.                CMP   param_tdisco,0         ; ¿se define disco ahora?
  575.                JE    fin_instalar           ; no: no hay más que hacer
  576.                CALL  mem_info               ; evaluar memoria del PC
  577.                CMP   tdisco,0               ; ¿se reservará memoria?
  578.                JE    fin_instalar           ; no: no hay más que hacer
  579.                CALL  mem_reserva            ; reservar memoria
  580.                JC    fin_instalar           ; fallo al reservarla
  581.                CALL  test_CPU               ; detectar 386 ó superior
  582.                CALL  adaptar_param          ; adaptar parámetros disco
  583.                CALL  preparar_BPB           ; BPB del nuevo disco
  584.                CALL  prep_driver            ; preparar el driver
  585.                CALL  formatear_tdsk         ; inic. BOOT, FAT y ROOT
  586. fin_instalar:  CALL  info_disco             ; informar sobre el disco
  587.                CMP   tipo_soporte,2
  588.                JE    res_largo              ; se utiliza memoria EMS
  589.                CMP   param_a,ON
  590.                JE    res_largo              ; se indicó /A
  591.                CALL  eval_xms
  592.                CALL  eval_ems
  593.                CMP   ems_kb,0
  594.                JE    res_corto              ; no hay memoria EMS
  595.                CMP   xms_kb,0
  596.                JNE   res_corto              ; la hay, pero también XMS
  597. res_largo:     MOV   AX,tam_proc_ems
  598.                MOV   rutina_larga,ON        ; dejar sitio a rutina EMS
  599.                JMP   bytes_res_ok
  600. res_corto:     MOV   AX,tam_proc_xms        ; dejar sitio a XMS/conv.
  601.                MOV   BX,tam_proc_con
  602.                CMP   AX,BX
  603.                JAE   bytes_res_ok
  604.                XCHG  AX,BX
  605. bytes_res_ok:  LDS   BX,CS:pcab_peticion
  606.                ADD   AX,OFFSET procesa_io
  607.                MOV   [BX].fin_resid_desp,AX ; reservar memoria para
  608.                MOV   [BX].fin_resid_segm,CS ; las rutinas a usar
  609.                MOV   AX,100h                ; instalación siempre Ok.
  610.                RET
  611. init           ENDP
  612.  
  613. ; ------------ Redefinición (invocada desde el AUTOEXEC.BAT o el DOS).
  614.  
  615. main           PROC  FAR
  616.                MOV   CS:modo,AUTOEXEC       ; ejecutando desde el DOS
  617.                CALL  obtDosVer              ; obtener versión del DOS
  618.                CALL  gestionar_ram          ; gestión de memoria
  619.                MOV   AX,_PRINCIPAL          ; programa de un segmento
  620.                MOV   DS,AX                  ; DS: -> _PRINCIPAL
  621.                MOV   BX,81h                 ; ES:BX línea de órdenes
  622.                CALL  procesar_param         ; procesar parámetros
  623.                CMP   param_h,ON
  624.                JE    exit_instalar          ; piden ayuda
  625.                PUSH  DS
  626.                POP   ES                     ; ES: --> _PRINCIPAL
  627.                CALL  errores_Dos
  628.                TEST  err_grave,0FFFFh
  629.                JNZ   exit_instalar          ; algún error grave
  630.                MOV   ES,segm_tdsk           ; ES: --> disco residente
  631.                CMP   param_a,ON
  632.                JNE   cabria_ems
  633.                CMP   ES:rutina_larga,ON
  634.                JE    cabria_ems             ; cabe la rutina EMS
  635.                OR    lista_err,ERROR2
  636. cabria_ems:    TEST  lista_err,ERROR0+ERROR2  ; ¿error sintaxis ó EMS?
  637.                JNZ   exit_instalar          ; sí: no modificar disco
  638.                CMP   param_tdiscof,ON
  639.                JNE   exit_instalar          ; no indicado nuevo tamaño
  640.                CMP   ES:tipo_soporte,0
  641.                JE    cont_instalar          ; no estaba formateado aún
  642.                CALL  desinstala             ; liberar memoria ocupada
  643. cont_instalar: CALL  mem_info               ; evaluar memoria del PC
  644.                CMP   tdisco,0               ; ¿se reservará memoria?
  645.                JE    exit_instalar          ; no: no hay más que hacer
  646.                CALL  mem_reserva            ; reservar memoria
  647.                JC    exit_instalar          ; fallo reservando memoria
  648.                CALL  test_CPU               ; detectar 386 ó superior
  649.                CALL  adaptar_param          ; adaptar parámetros disco
  650.                CALL  preparar_BPB           ; BPB del nuevo disco
  651.                CALL  relocalizar            ; autoreubicación de TDSK
  652.                CALL  prep_driver            ; preparar el driver
  653.                CALL  formatear_tdsk         ; BOOT, FAT y ROOT
  654. exit_instalar: CALL  info_disco             ; informar sobre el disco
  655.                CMP   tipo_soporte,3         ; ¿memoria convencional?
  656.                JNE   fin_no_res             ; no usada
  657.                CALL  renombrar_mcb          ; cambiar nombre del MCB
  658.                MOV   DX,6                   ; usada: 96 bytes de PSP
  659.                MOV   AX,3100h
  660.                INT   21h                    ; terminar residente
  661. fin_no_res:    CALL  set_errorlevel         ; preparar ERRORLEVEL
  662.                MOV   AH,4Ch
  663.                INT   21h                    ; final normal
  664. main           ENDP
  665.  
  666. ; ------------ Inicializar la variable con la versión del DOS
  667.  
  668. obtDosVer      PROC
  669.                XPUSH <AX,BX,CX,DX>
  670.                MOV   AH,30h
  671.                INT   21h
  672.                XCHG  AH,AL
  673.                MOV   CS:dosver,AX
  674.                XPOP  <DX,CX,BX,AX>
  675.                RET
  676. obtDosVer      ENDP
  677.  
  678. ; ------------ Determinar segmento del PSP, último segmento de memoria
  679. ;              y liberar espacio de entorno. Se modifica también el
  680. ;              bloque de memoria de TDSK reduciéndolo a 96 bytes: esto
  681. ;              provoca la creación de un bloque de control de memoria
  682. ;              en el offset 96 del PSP, lo cual no es peligroso. El
  683. ;              objetivo de esta maniobra es poder asignar memoria al
  684. ;              disco después (sólo si hace falta memoria convencional)
  685. ;              usando los servicios estándar del DOS.
  686.  
  687. gestionar_ram  PROC
  688.                MOV   CS:segm_psp,DS         ; indicar segmento del PSP
  689.                MOV   AX,DS:[2]              ; segmento más alto
  690.                MOV   CS:top_ram,AX          ; indicar tope de memoria
  691.                PUSH  ES
  692.                MOV   ES,DS:[2Ch]            ; segmento del entorno
  693.                MOV   AH,49h
  694.                INT   21h                    ; liberar área de entorno
  695.                POP   ES                     ; ES: -> PSP
  696.                MOV   BX,6
  697.                MOV   AH,4Ah                 ; hacer creer al DOS que
  698.                INT   21h                    ; TDSK ocupa sólo 96 bytes
  699.                RET
  700. gestionar_ram  ENDP
  701.  
  702. ; ------------ Leer los parámetros de la línea de comandos (ES:BX).
  703. ;              Se inicializan las correspondientes variables. En caso
  704. ;              de error, se dejan a cero las variables y se acumula en
  705. ;              «lista_err» un ERROR0 (error de sintaxis).
  706.  
  707. procesar_param PROC
  708.                CALL  busca_param       ; saltar delimitadores
  709.                JC    fin_param         ; no hay más parámetros
  710.                CALL  param_barra       ; gestionar parámetro tipo "/A"
  711.                JC    procesar_param    ; era parámetro tipo "/A"
  712.                MOV   param_tdisco,AX   ; es numérico: tamaño del disco
  713.                MOV   param_tdiscof,ON  ; parámetro de tamaño indicado
  714. p_param2:      CALL  busca_param
  715.                JC    fin_param
  716.                CALL  param_barra
  717.                JC    p_param2
  718.                MOV   param_tsect,AX    ; tamaño de sector
  719. p_param3:      CALL  busca_param
  720.                JC    fin_param
  721.                CALL  param_barra
  722.                JC    p_param3
  723.                MOV   param_tdir,AX     ; entradas al directorio
  724. p_param4:      CALL  busca_param
  725.                JC    fin_param
  726.                CALL  param_barra
  727.                JC    p_param4
  728.                MOV   param_tcluster,AX ; tamaño de cluster
  729. p_param5:      CALL  busca_param
  730.                JC    fin_param
  731.                CALL  param_barra       ; últimas opciones posibles
  732.                JC    p_param5
  733. fin_param:     CALL  validacion        ; validación de parámetros
  734.                RET
  735. procesar_param ENDP
  736.  
  737. param_barra    PROC
  738.                CMP   AX,"e/"           ; ¿indicado /E?
  739.                JNE   p_exp1?
  740.                MOV   param_e,ON
  741.                JMP   p_barra_exit
  742. p_exp1?:       CMP   AX,"a/"           ; ¿indicado /A?
  743.                JNE   p_exp2?
  744. p_exp:         MOV   param_a,ON
  745.                JMP   p_barra_exit
  746. p_exp2?:       CMP   AX,"x/"           ; /A y /X son equivalentes
  747.                JE    p_exp
  748.                CMP   AX,"c/"           ; ¿indicado /C?
  749.                JNE   p_ayuda?
  750.                MOV   param_c,ON
  751.                JMP   p_barra_exit
  752. p_ayuda?:      CMP   AX,"h/"           ; ¿indicado /H?
  753.                JNE   p_exit?
  754. p_ayuda:       MOV   param_h,ON
  755.                JMP   p_barra_exit
  756. p_exit?:       CMP   AX,"?/"           ; /H y /? son equivalentes
  757.                JE    p_ayuda
  758.                CMP   AX,"m/"           ; ¿indicado /M?
  759.                JNE   param_id?
  760.                MOV   param_m,ON
  761.                JMP   p_barra_exit
  762. param_id?:     CMP   AX,"i/"           ; ¿indicado /I= o /I:?
  763.                JNE   param_fats?
  764.                ADD   BX,3
  765.                CMP   BYTE PTR ES:[BX-1],'='
  766.                JE    p_id_ok
  767.                CMP   BYTE PTR ES:[BX-1],':'
  768.                JNE   param_b_mal
  769. p_id_ok:       CALL  obt_num           ; leer código telefónico
  770.                MOV   param_i,AX
  771.                SUB   BX,2
  772.                JMP   p_barra_exit
  773. param_fats?:   CMP   AX,"f/"           ; ¿indicado /F= o /F:?
  774.                JNE   param_unidad?
  775.                ADD   BX,3
  776.                CMP   BYTE PTR ES:[BX-1],'='
  777.                JE    p_f_ok
  778.                CMP   BYTE PTR ES:[BX-1],':'
  779.                JNE   param_b_mal
  780. p_f_ok:        CALL  obt_num           ; leer número de FATs
  781.                MOV   param_f,AX
  782.                SUB   BX,2
  783.                JMP   p_barra_exit
  784. param_unidad?: CMP   AH,':'            ; ¿parámetro de unidad?
  785.                JNE   param_num?
  786.                SUB   AL,'a'-1
  787.                MOV   param_unidad,AL
  788.                JMP   p_barra_exit
  789. param_num?:    CMP   AL,'/'
  790.                JNE   param_num         ; puede ser número
  791. param_b_mal:   OR    lista_err,ERROR0
  792. param_num:     CALL  obt_num           ; es parámetro numérico: leerlo
  793.                CLC                     ; no es parámetro barrado
  794.                RET
  795. p_barra_exit:  ADD   BX,2              ; saltar este parámetro
  796.                STC                     ; es parámetro barrado
  797.                RET
  798. param_barra    ENDP
  799.  
  800. validacion     PROC
  801.                MOV   AX,0FFFFh
  802.                CMP   AX,param_tdisco   ; ¿números correctos?
  803.                JE    sintax_err
  804.                CMP   AX,param_tsect
  805.                JE    sintax_err
  806.                CMP   AX,param_tdir
  807.                JE    sintax_err
  808.                CMP   AX,param_tcluster
  809.                JE    sintax_err
  810.                CMP   param_tdisco,0
  811.                JE    valida_tsect      ; no indicado tamaño (o 0)
  812.                CMP   param_tdisco,8
  813.                JB    sintax_err
  814.                CMP   param_tdisco,65534
  815.                JA    sintax_err
  816. valida_tsect:  MOV   AX,param_tsect
  817.                CMP   AX,0
  818.                JE    valida_tclus      ; no indicado tamaño de sector
  819.                CMP   AX,32
  820.                JE    valida_tclus
  821.                CMP   AX,64
  822.                JE    valida_tclus
  823.                CMP   AX,128
  824.                JE    valida_tclus
  825.                CMP   AX,256
  826.                JE    valida_tclus
  827.                CMP   AX,512
  828.                JE    valida_tclus
  829.                CMP   AX,1024
  830.                JE    valida_tclus
  831.                CMP   AX,2048
  832.                JNE   sintax_err
  833. valida_tclus:  CMP   param_tcluster,256
  834.                JAE   sintax_err        ; debe estar entre 0..255
  835.                CMP   param_f,1
  836.                JB    pf_a1             ; /F=1 ó /F=2 exclusivamente
  837.                CMP   param_f,2         ; si no, forzarlo y perdonar
  838.                JBE   fin_validar
  839.                MOV   param_f,2
  840.                JMP   fin_validar
  841. pf_a1:         MOV   param_f,1
  842.                JMP   fin_validar
  843. sintax_err:    MOV   param_tdiscof,OFF ; no definir disco ahora
  844.                XOR   AX,AX
  845.                MOV   param_tdisco,AX
  846.                MOV   param_tsect,AX
  847.                MOV   param_tdir,AX
  848.                MOV   param_tcluster,AX
  849.                OR    lista_err,ERROR0  ; aviso de error de sintaxis
  850. fin_validar:   RET
  851. validacion     ENDP
  852.  
  853. salta_nombre   PROC                    ; saltar nombre del driver en
  854.                MOV   AL,ES:[BX]        ; línea de órdenes del CONFIG
  855.                INC   BX
  856.                CMP   AL,' '
  857.                JE    fin_nombre
  858.                CMP   AL,9
  859.                JE    fin_nombre
  860.                CMP   AL,0Dh
  861.                JE    fin_nombre
  862.                CMP   AL,0Ah
  863.                JE    fin_nombre
  864.                AND   AL,AL
  865.                JZ    fin_nombre        ; necesario para DOS 2.x
  866.                JMP   salta_nombre
  867. fin_nombre:    RET
  868. salta_nombre   ENDP
  869.  
  870. busca_param    PROC                    ; saltar delimitadores
  871.                DEC   BX
  872. p_delimit:     INC   BX
  873.                MOV   AX,ES:[BX]
  874.                CMP   AL,' '
  875.                JE    p_delimit         ; espacio en blanco
  876.                CMP   AL,9
  877.                JE    p_delimit         ; tabulador
  878.                CMP   AL,13
  879.                JE    p_final           ; CR ó LF indican el final
  880.                CMP   AL,10
  881.                JE    p_final
  882.                OR    AX,"  "           ; poner en minúsculas
  883.                CLC
  884.                RET
  885. p_final:       STC                     ; se acabaron los parámetros
  886.                RET
  887. busca_param    ENDP
  888.  
  889. obt_num        PROC                    ; leer número: devolver 65535
  890.                XPUSH <CX,DX,SI>        ; si hay error
  891.                XOR   AX,AX             ; número en proceso de creación
  892. otro_digito:   MOV   CL,ES:[BX]
  893.                CMP   CL,'0'
  894.                JB    no_digito
  895.                CMP   CL,'9'
  896.                JBE   digito_ok
  897. no_digito:     CMP   CL,' '            ; posibles delimitadores...
  898.                JE    fin_num
  899.                CMP   CL,9
  900.                JE    fin_num
  901.                CMP   CL,13
  902.                JE    fin_num
  903.                CMP   CL,10
  904.                JE    fin_num
  905.                CMP   CL,'/'
  906.                JE    fin_num
  907.                JMP   num_incorr
  908. digito_ok:     XOR   DX,DX
  909.                MOV   SI,10
  910.                MUL   SI                ; AX = AX * 10
  911.                JC    num_incorr
  912.                XOR   CH,CH
  913.                SUB   CL,'0'
  914.                ADD   AX,CX             ; AX = AX + dato
  915.                JC    num_incorr
  916.                INC   BX
  917.                JMP   otro_digito
  918. num_incorr:    MOV   AX,65535          ; indicar valor incorrecto
  919. fin_num:       XPOP  <SI,DX,CX>
  920.                RET
  921. obt_num        ENDP
  922.  
  923. ; ------------ Detectar errores que se pueden producir sólo en la
  924. ;              línea de comandos.
  925.  
  926. errores_Dos    PROC
  927.                PUSH  ES
  928.                CMP   dosver,200h       ; necesario DOS 2.x+
  929.                JAE   existe_tdsk?
  930.                OR    err_grave,ERROR0  ; error de DOS incorrecto
  931.                JMP   fin_err_Dos
  932. existe_tdsk?:  CALL  reside_tdsk?      ; ¿instalado TURBODSK?
  933.                CMP   segm_tdsk,0
  934.                JNE   busca_unidad      ; ya instalado
  935.                OR    err_grave,ERROR1  ; error: TURBODSK no instalado
  936.                JMP   fin_err_Dos
  937. busca_unidad:  MOV   ES,segm_tdsk      ; ES: -> disco virtual
  938.                CMP   param_unidad,0
  939.                JE    disco_defecto     ; no se indicó letra de unidad
  940.                CALL  obtener_segm      ; segmento del TDSK indicado
  941.                JC    fin_err_Dos       ; fallo (no es unidad TDSK)
  942. disco_defecto: CALL  max_sector        ; obtener mayor sector
  943.                MOV   BX,param_tsect
  944.                CMP   BX,AX
  945.                JBE   fin_err_Dos       ; tamaño de sector correcto
  946.                OR    lista_err,ERROR3  ; el tamaño no definible ahora
  947.                MOV   param_tsect,0     ; ignorar tamaño indicado
  948. fin_err_Dos:   CALL  test32Mb
  949.                CALL  testWin
  950.                POP   ES
  951.                RET
  952. errores_Dos    ENDP
  953.  
  954. ; ------------ Detectar errores que se pueden producir sólo desde
  955. ;              el CONFIG.SYS
  956.  
  957. errores_config PROC
  958.                CMP   param_unidad,0
  959.                JE    no_unidad
  960.                OR    lista_err,ERROR1
  961. no_unidad:     CMP   param_c,ON
  962.                JNE   fin_err_con
  963.                OR    lista_err,ERROR1
  964. fin_err_con:   CALL  test32Mb
  965.                RET
  966. errores_config ENDP
  967.  
  968. ; ------------ Preparar valor de ERRORLEVEL para el retorno.
  969.  
  970. set_errorlevel PROC
  971.                MOV   AL,255
  972.                TEST  err_grave,ERROR1  ; ¿TDSK no instalado?
  973.                JNZ   fin_cod_ok
  974.                DEC   AL
  975.                TEST  err_grave,ERROR2  ; ¿unidad incorrecta?
  976.                JNZ   fin_cod_ok
  977.                DEC   AL
  978.                TEST  err_grave,ERROR3  ; ¿dentro de Windows?
  979.                JNZ   fin_cod_ok
  980.                DEC   AL
  981.                TEST  lista_err,ERROR0  ; error de sintaxis
  982.                JNZ   fin_cod_ok
  983.                MOV   AL,BYTE PTR ES:mem_handle  ; handle XMS/EMS
  984.                CMP   ES:tipo_soporte,0
  985.                JNE   fin_cod_ok
  986.                MOV   AL,0              ; disco no formateado
  987. fin_cod_ok:    RET
  988. set_errorlevel ENDP
  989.  
  990. ; ------------ Obtener mayor tamaño de sector definido en el sistema.
  991.  
  992. max_sector     PROC
  993.                XPUSH <BX,ES>
  994.                MOV   AH,52h
  995.                INT   21h               ; Get List of Lists
  996.                ADD   BX,10h
  997.                CMP   CS:dosver,30Ah
  998.                JAE   psect_ok
  999.                INC   BX                ; DOS anterior al 3.1
  1000. psect_ok:      MOV   AX,ES:[BX]        ; mayor tamaño de sector
  1001.                XPOP  <ES,BX>           ; definido por cualquier disp.
  1002.                RET
  1003. max_sector     ENDP
  1004.  
  1005. ; ------------ Si el disco es de más de 32 Mb, comprobar si el sector
  1006. ;              es de al menos 1024 bytes.
  1007.  
  1008. test32Mb       PROC
  1009.                CMP   param_tdisco,32768
  1010.                JBE   fin32mb
  1011.                CMP   param_tsect,1024
  1012.                JAE   fin32mb
  1013.                OR    lista_err,ERROR15      ; sector de menos de 1024
  1014.                MOV   param_tdisco,32768     ; evitar fallo posterior
  1015. fin32mb:       RET
  1016. test32Mb       ENDP
  1017.  
  1018. ; ------------ Desde Windows, no se permite redefinir el disco.
  1019.  
  1020. testWin        PROC
  1021.                CMP   param_tdiscof,ON
  1022.                JNE   fin_testWin       ; no redefinido el disco
  1023.                CMP   dosver,300h
  1024.                JB    fin_testWin       ; no buscar Windows en DOS 2.x
  1025.                MOV   AX,1600h
  1026.                INT   2Fh
  1027.                AND   AL,AL             ; ¿Windows en modo extendido?
  1028.                JZ    noWinEnh
  1029.                CMP   AL,80h            ; ¿Windows en modo extendido?
  1030.                JE    noWinEnh
  1031. siWin:         OR    err_grave,ERROR3  ; estamos dentro de Windows
  1032.                JMP   fin_testWin
  1033. noWinEnh:      MOV   AX,4680h
  1034.                INT   2Fh
  1035.                AND   AX,AX
  1036.                JZ    siWin             ; Windows en modo real/estándar
  1037. fin_testWin:   RET
  1038. testWin        ENDP
  1039.  
  1040. ; ------------ Verificar la presencia en memoria de TURBODSK. Se
  1041. ;              inicializa «segm_tdsk» y «letra_unidad» indicando dónde
  1042. ;              reside el primer dispositivo TURBODSK de todos los que
  1043. ;              puede haber instalados. La letra de la unidad se halla
  1044. ;              «contando» y no del propio TDSK residente.
  1045.  
  1046. reside_tdsk?   PROC
  1047.                XPUSH <AX,DX,SI>
  1048.                CALL  lista_discos
  1049.                LEA   SI,area_trabajo-4
  1050.                XOR   DL,DL
  1051. busca_final:   ADD   SI,4
  1052.                CMP   WORD PTR [SI],0
  1053.                JNE   busca_final       ; ir al final de la tabla
  1054. busca_tdsk:    SUB   SI,4
  1055.                ADD   DL,[SI+2]
  1056.                CMP   SI,OFFSET area_trabajo
  1057.                JB    fin_busca         ; no reside (segm_tdsk = 0)
  1058.                CMP   BYTE PTR [SI+3],1
  1059.                JNE   busca_tdsk
  1060.                MOV   AX,[SI]           ; encontrada unidad TURBODSK
  1061.                MOV   segm_tdsk,AX
  1062.                ADD   DL,'A'-1
  1063.                MOV   letra_unidad,DL
  1064. fin_busca:     XPOP  <SI,DX,AX>
  1065.                RET
  1066. reside_tdsk?   ENDP
  1067.  
  1068. ; ------------ Obtener el segmento de la unidad TURBODSK indicada, si
  1069. ;              existe, accediendo a una tabla de dispositivos que se
  1070. ;              crea. A la salida, CF=1 si esa unidad no es TURBODSK.
  1071.  
  1072. obtener_segm   PROC
  1073.                CALL  lista_discos
  1074.                LEA   SI,area_trabajo-4
  1075.                XOR   AL,AL             ; disco A:
  1076. busca_ultimo:  ADD   SI,4
  1077.                CMP   WORD PTR [SI],0
  1078.                JNE   busca_ultimo      ; realmente, el primero
  1079. recorre_dsks:  SUB   SI,4
  1080.                ADD   AL,[SI+2]         ; siguiente unidad
  1081.                CMP   SI,OFFSET area_trabajo
  1082.                JB    tdsk_no_hay
  1083.                CMP   BYTE PTR [SI+3],1
  1084.                JNE   recorre_dsks
  1085.                CMP   AL,param_unidad   ; disco TDSK: ¿es el buscado?
  1086.                JNE   recorre_dsks
  1087.                ADD   AL,'A'-1
  1088.                MOV   letra_unidad,AL   ; inicializar letra de unidad
  1089.                MOV   AX,[SI]
  1090.                MOV   segm_tdsk,AX      ; inicializar segmento
  1091.                MOV   ES,AX
  1092.                CLC
  1093.                RET
  1094. tdsk_no_hay:   OR    err_grave,ERROR2  ; unidad indicada no es TDSK
  1095.                STC
  1096.                RET
  1097. obtener_segm   ENDP
  1098.  
  1099. ; ------------ Colocar nuevo gestor de INT 19h al instalar TDSK desde
  1100. ;              el CONFIG.SYS. En algunos entornos multitarea basados
  1101. ;              en el modo virtual-86 del 386 y superiores, si no se
  1102. ;              libera la memoria EMS/XMS tras una cancelación de la
  1103. ;              tarea virtual, ésta queda permanentemente ocupada hasta
  1104. ;              un reset «frío» del sistema, sin poder ser aprovechada
  1105. ;              por los demás procesos. La INT 19h se ejecuta cuando la
  1106. ;              tarea en curso va a ser inminentemente cancelada por el
  1107. ;              sistema, y TURBODSK la intercepta para poder liberar la
  1108. ;              memoria EMS/XMS en el último instante. La rutina que
  1109. ;              controla INT 19h contiene código de 286, por lo que se
  1110. ;              chequea la presencia de este procesador.
  1111.  
  1112. desvia_int19   PROC
  1113.                XPUSH <BX,DS,ES>
  1114.                MOV   BX,CS
  1115.                MOV   DS,BX
  1116.                CALL  test_CPU
  1117.                CMP   cpu286,ON
  1118.                JNE   fin_desvia19      ; no es 286 ó superior
  1119.                MOV   AX,3519h
  1120.                INT   21h               ; ES:BX anterior INT 19h
  1121.                MOV   ant19off,BX
  1122.                MOV   ant19seg,ES
  1123.                LEA   DX,nueva_int19
  1124.                MOV   AX,2519h
  1125.                INT   21h               ; nueva rutina de control
  1126. fin_desvia19:  XPOP  <ES,DS,BX>
  1127.                RET
  1128. desvia_int19   ENDP
  1129.  
  1130. ; ------------ Obtener la letra de la unidad de disco definida. Esta
  1131. ;              rutina se invoca sólo desde CONFIG.SYS con DS:BX
  1132. ;              apuntando a la cabecera de petición de la orden INIT.
  1133.  
  1134. inic_letra     PROC
  1135.                XPUSH <AX,BX,SI,DS>
  1136.                MOV   AL,[BX].nuevo_disco    ; unidad en DOS 3.0+
  1137.                ADD   AL,'A'
  1138.                PUSH  CS
  1139.                POP   DS                     ; DS -> _PRINCIPAL
  1140.                CMP   dosver,300h
  1141.                JAE   letra_ok
  1142.                CALL  lista_discos           ; hallar unidad en DOS 2.x
  1143.                LEA   SI,area_trabajo
  1144.                XOR   AL,AL                  ; cuenta de discos
  1145. cuenta_discos: ADD   AL,[SI+2]
  1146.                ADD   SI,4
  1147.                CMP   WORD PTR [SI],0
  1148.                JNE   cuenta_discos
  1149.                ADD   AL,'A'
  1150. letra_ok:      MOV   letra_unidad,AL        ; guardar letra de unidad
  1151.                XPOP  <DS,SI,BX,AX>
  1152.                RET
  1153. inic_letra     ENDP
  1154.  
  1155. ; ------------ Crear una lista de todos los dispositivos de bloque
  1156. ;              del sistema. La lista tiene una entrada de 4 bytes
  1157. ;              para cada dispositivo: los dos primeros indican el
  1158. ;              segmento en que reside, el siguiente el número de
  1159. ;              unidades que controla y el último vale 1 ó 0 para
  1160. ;              indicar si es una unidad TDSK o no. El final de la
  1161. ;              lista lo señaliza un segmento igual a 0.
  1162.  
  1163. lista_discos   PROC
  1164.                XPUSH <AX,BX,CX,DX,SI,DI,ES>
  1165.                MOV   AH,52h            ; "Get list of lists"
  1166.                INT   21h               ; obtener puntero en ES:BX
  1167.                MOV   CX,17h            ; supuesto DOS 2.x
  1168.                CMP   dosver,300h
  1169.                JB    pdisp_ok
  1170.                MOV   CX,28h            ; supuesto DOS 3.0x
  1171.                CMP   dosver,30Ah
  1172.                JB    pdisp_ok
  1173.                MOV   CX,22h            ; versiones del DOS superiores
  1174. pdisp_ok:      ADD   BX,CX
  1175.                LEA   DI,area_trabajo-4 ; tabla de dispositivos-4
  1176. disp_otro:     ADD   DI,4
  1177. disp_skip:     LES   BX,ES:[BX]        ; siguiente dispositivo
  1178.                CMP   BX,-1
  1179.                JE    disp_fin
  1180.                TEST  BYTE PTR ES:[BX+5],80h
  1181.                JNZ   disp_skip         ; es dispositivo de caracteres
  1182.                MOV   CL,ES:[BX+10]     ; es de bloques
  1183.                MOV   [DI],ES           ; anotar dirección
  1184.                MOV   [DI+2],CL
  1185.                MOV   BYTE PTR [DI+3],0 ; de momento, no es TDSK
  1186.                PUSH  DI
  1187.                LEA   SI,id_tdsk        ; identificación de TURBODSK
  1188.                MOV   DI,SI
  1189.                MOV   CX,5
  1190.                CLD
  1191.                REP   CMPSB             ; ¿es TURBODSK?
  1192.                POP   DI
  1193.                JNE   disp_otro         ; es de bloques, pero no TDSK
  1194.                MOV   AX,ES:cs_tdsk     ; segmento real de TDSK
  1195.                MOV   [DI],AX           ; corregir dirección en tabla
  1196.                INC   BYTE PTR [DI+3]   ; indicar dispositivo TDSK
  1197.                JMP   disp_otro         ; buscar hasta completar tabla
  1198. disp_fin:      MOV   WORD PTR [DI],0   ; final de la lista
  1199.                XPOP  <ES,DI,SI,DX,CX,BX,AX>
  1200.                RET
  1201. lista_discos   ENDP
  1202.  
  1203. ; ------------ Liberar la memoria ocupada por un TURBODSK residente.
  1204.  
  1205. desinstala     PROC
  1206.                MOV   DX,ES:mem_handle
  1207.                MOV   AL,ES:tipo_soporte
  1208.                DEC   AL
  1209.                JZ    libera_ext        ; liberar memoria extendida
  1210.                DEC   AL
  1211.                JZ    libera_exp        ; liberar memoria expandida
  1212.                PUSH  ES
  1213.                MOV   ES,DX
  1214.                MOV   AH,49h            ; liberar memoria convencional:
  1215.                INT   21h
  1216.                POP   ES
  1217.                PUSH  ES
  1218.                PUSHF                   ; condición de error
  1219.                MOV   ES,ES:tdsk_psp    ; liberar PSP residente
  1220.                MOV   AH,49h
  1221.                INT   21h
  1222.                PUSHF
  1223.                CMP   dosver,31Eh
  1224.                JA    mcb_ok            ; DOS 3.31+: el MCB es correcto
  1225.                MOV   AX,ES
  1226.                DEC   AX
  1227.                MOV   ES,AX
  1228.                MOV   DI,8
  1229.                MOV   CX,DI
  1230.                CLD
  1231.                MOV   AL,' '
  1232.                REP   STOSB             ; hasta DOS 3.30 borrar nombre
  1233. mcb_ok:        POPF
  1234.                JNC   lib_con_ok?       ; liberado correctamente
  1235.                POPF
  1236.                POP   ES
  1237.                STC                     ; ha habido fallo
  1238.                JMP   desinstalado
  1239. lib_con_ok?:   POPF                    ; recuperar condición de error
  1240.                POP   ES
  1241.                JMP   desinstalado
  1242. libera_ext:    MOV   AH,0Ah
  1243.                CALL  ES:xms_driver
  1244.                CMP   AX,1
  1245.                JE    desinstalado      ; éxito al liberar memoria XMS
  1246.                STC
  1247.                JMP   desinstalado      ; fallo
  1248. libera_exp:    MOV   AH,45h
  1249.                INT   67h
  1250.                CMP   AH,0
  1251.                JE    desinstalado
  1252.                CMP   AH,82h            ; ¿EMM ocupado?
  1253.                JE    libera_exp
  1254.                STC                     ; fallo al liberar memoria EMS
  1255. desinstalado:  MOV   ES:tipo_soporte,0 ; disco «no formateado»
  1256.                JNC   desins_ok
  1257.                OR    lista_err,ERROR14 ; fallo al liberar memoria
  1258.                STC
  1259. desins_ok:     RET
  1260. desinstala     ENDP
  1261.  
  1262. ; ------------ Determinar la configuración del sistema: tipos de
  1263. ;              memoria y cantidad de la misma. Se indica en «tdisco»
  1264. ;              un valor 0 si no se define ahora el disco, sea cual sea
  1265. ;              el motivo del fallo, y se actualiza la variable que
  1266. ;              indica los mensajes de error y advertencia a imprimir.
  1267.  
  1268. mem_info       PROC
  1269.                MOV   tdisco,0          ; ley de Murphy
  1270.                CALL  eval_xms          ; inicializar «xms_kb»
  1271.                CALL  eval_ems          ; inicializar «ems_kb»
  1272.                CALL  eval_con          ; inicializar «con_kb»
  1273.                MOV   AX,param_tdisco   ; cantidad de memoria necesaria
  1274.                CMP   param_a,ON
  1275.                JNE   no_ems            ; no solicitan memoria EMS
  1276.                MOV   BX,ems_kb         ; solicitan memoria EMS...
  1277.                AND   BX,BX
  1278.                JNZ   usara_ems
  1279.                OR    lista_err,ERROR7  ; no hay memoria EMS disponible
  1280.                JMP   mem_infoado
  1281. usara_ems:     CMP   AX,BX
  1282.                JBE   usar_ems          ; piden algo razonable
  1283.                MOV   AX,BX
  1284.                OR    lista_err,ERROR4  ; rebajado el tamaño
  1285. usar_ems:      MOV   tdisco,AX
  1286.                MOV   tipo_soporte,2    ; indicar memoria expandida
  1287.                JMP   mem_infoado
  1288. no_ems:        CMP   param_e,ON
  1289.                JNE   no_xms            ; no solicitan memoria XMS
  1290.                MOV   BX,xms_kb         ; solicitan memoria XMS...
  1291.                AND   BX,BX
  1292.                JNZ   usara_xms
  1293.                OR    lista_err,ERROR6  ; no hay memoria XMS disponible
  1294.                JMP   mem_infoado
  1295. usara_xms:     CMP   AX,BX
  1296.                JBE   usar_xms          ; piden algo razonable
  1297.                MOV   AX,BX
  1298.                OR    lista_err,ERROR4  ; rebajado el tamaño
  1299. usar_xms:      MOV   tdisco,AX
  1300.                MOV   tipo_soporte,1    ; indicar memoria extendida
  1301.                JMP   mem_infoado
  1302. no_xms:        CMP   param_c,ON
  1303.                JNE   no_con            ; no solicitan memoria conv.
  1304. forzar_con:    MOV   BX,con_kb         ; solicitan memoria conv. ...
  1305.                AND   BX,BX
  1306.                JNZ   usara_con
  1307.                OR    lista_err,ERROR10 ; no hay memoria conv. libre
  1308.                JMP   mem_infoado
  1309. usara_con:     CMP   AX,BX
  1310.                JBE   usar_con          ; piden algo razonable
  1311.                MOV   AX,BX
  1312.                OR    lista_err,ERROR4  ; rebajado el tamaño
  1313. usar_con:      MOV   tdisco,AX
  1314.                MOV   tipo_soporte,3    ; indicar memoria convencional
  1315.                JMP   mem_infoado
  1316. no_con:        CMP   AX,xms_kb         ; no indicado tipo de memoria
  1317.                JBE   usar_xms          ; intentar emplear memoria XMS
  1318.                CMP   ES:rutina_larga,ON
  1319.                JE    valdria_ems
  1320.                MOV   BX,xms_kb
  1321.                CMP   BX,0              ; imposible usar EMS
  1322.                JNE   usara_xms         ; queda algo de XMS
  1323.                JMP   usar_con?
  1324. valdria_ems:   MOV   BX,ems_kb
  1325.                CMP   AX,BX
  1326.                JA    nv_ems
  1327.                JMP   usar_ems          ; emplear memoria EMS
  1328. nv_ems:        MOV   BX,ems_kb
  1329.                OR    BX,xms_kb
  1330.                JZ    usar_con?         ; no hay un ápice de XMS ni EMS
  1331.                OR    lista_err,ERROR4  ; rebajado el tamaño solicitado
  1332.                MOV   AX,xms_kb
  1333.                CMP   AX,ems_kb
  1334.                JAE   usar_xms          ; hay más o igual XMS que EMS
  1335.                MOV   AX,ems_kb
  1336.                JMP   usar_ems          ; hay algo de EMS (más que XMS)
  1337. usar_con?:     CMP   modo,AUTOEXEC
  1338.                JE    forzar_con        ; sólo se puede usar mem. conv.
  1339.                OR    lista_err,ERROR5  ; ho hay memoria EMS ni XMS
  1340. mem_infoado:   RET
  1341. mem_info       ENDP
  1342.  
  1343.                ; ---- Calcular memoria extendida disponible
  1344.  
  1345. eval_xms       PROC
  1346.                PUSH  ES
  1347.                MOV   AX,352Fh
  1348.                INT   21h               ; dirección de INT 2Fh en ES:BX
  1349.                MOV   AX,ES
  1350.                AND   AX,AX
  1351.                JZ    xms_ok            ; apunta a 0000:XXXX (DOS 2.x)
  1352.                MOV   AX,4300h
  1353.                INT   2Fh
  1354.                CMP   AL,80h            ; ¿hay controlador XMS?
  1355.                JNE   xms_ok
  1356.                MOV   AX,4310h          ; obtener su dirección
  1357.                INT   2Fh
  1358.                MOV   xms_segm,ES
  1359.                MOV   xms_desp,BX
  1360.                MOV   AH,8
  1361.                CALL  xms_driver        ; preguntar memoria libre
  1362.                AND   AX,AX
  1363.                JNZ   xms_kb_ok         ; no hubo fallo
  1364.                CMP   BL,0A0h
  1365.                JE    xms_kb_ok         ; asignada ya toda la memoria
  1366.                TEST  BL,80h
  1367.                JZ    xms_kb_ok         ; no hay memoria XMS disponible
  1368.                OR    lista_err,ERROR8  ; fallo real del controlador
  1369. xms_kb_ok:     CMP   AX,8              ; mayor bloque XMS disponible
  1370.                JB    xms_ok
  1371.                MOV   xms_kb,AX         ; mínimo necesario: 8 Kb
  1372. xms_ok:        POP   ES
  1373.                RET
  1374. eval_xms       ENDP
  1375.  
  1376.                ; ---- Calcular memoria expandida disponible. Si la
  1377.                ;      versión del EMM es 4.0 o superior, las páginas
  1378.                ;      de memoria expandida pueden no ser contiguas:
  1379.                ;      buscar una que diste 32 Kb de la página 0.
  1380.  
  1381. eval_ems       PROC
  1382.                PUSH  ES
  1383.                MOV   AX,3567h
  1384.                INT   21h               ; vector de INT 67h en ES:BX
  1385.                MOV   DI,10
  1386.                LEA   SI,emm_id
  1387.                MOV   CX,8
  1388.                CLD
  1389.                REP   CMPSB             ; ¿instalado controlador EMS?
  1390.                JE    ems_existe
  1391.                JMP   ems_ok
  1392. ems_existe:    MOV   CX,8000h          ; nº de intentos prudente
  1393. emm_llama:     MOV   AH,40h
  1394.                INT   67h
  1395.                AND   AH,AH
  1396.                JZ    emm_responde
  1397.                CMP   AH,82h
  1398.                LOOPE emm_llama
  1399. emm_fatal:     OR    lista_err,ERROR9  ; fallo del EMM
  1400.                JMP   ems_ok
  1401. emm_responde:  MOV   AH,41h
  1402.                INT   67h
  1403.                AND   AH,AH
  1404.                JZ    emm_pag_ok
  1405.                CMP   AH,82h
  1406.                JE    emm_responde      ; reintentar (EMM ocupado)
  1407.                JMP   emm_fatal
  1408. emm_pag_ok:    MOV   ems_pagina0,BX    ; inicializar página EMS
  1409.                ADD   BX,0C00h
  1410.                MOV   ems_paginai,BX
  1411.                MOV   ems_pagni,3       ; página alternativa: la 3
  1412.                MOV   AH,46h
  1413.                INT   67h               ; obtener versión del EMM
  1414.                CMP   AL,40h
  1415.                JB    emm_obt_kb        ; versión anterior a la 4.0
  1416.                MOV   ems4,ON
  1417. emm_obt_pag:   XPUSH <ES,DS>
  1418.                POP   ES
  1419.                MOV   AX,5800h          ; obtener dirección de páginas
  1420.                LEA   DI,area_trabajo
  1421.                INT   67h
  1422.                POP   ES
  1423.                AND   AH,AH
  1424.                JZ    emm_pags_ok
  1425.                CMP   AH,82h
  1426.                JE    emm_obt_pag
  1427.                JMP   emm_fatal
  1428. emm_pags_ok:   XOR   DX,DX
  1429.                CALL  emm_busca_pag     ; buscar página 0
  1430.                JC    emm_fatal
  1431.                MOV   ems_pagina0,BX
  1432. ems_busca_i:   INC   DX                ; buscar la siguiente
  1433.                CMP   DX,5              ; la 5ª y siguientes no valen
  1434.                JE    emm_fatal         ;            ├──────┤
  1435.                CALL  emm_busca_pag     ;            │      │
  1436.                JC    emm_fatal         ;     ┌>   ┌>├──────┤<-- pág i
  1437.                MOV   ems_paginai,BX    ;0C00h│ 32 │ │      │
  1438.                MOV   ems_pagni,DL      ; pá  │ Kb │ ├──────┤
  1439.                SUB   BX,ems_pagina0    ; rra │    │ │      │
  1440.                JNC   bxpositivo        ; fos │    └>├──────┤
  1441.                NEG   BX                ;     │      │      │
  1442. bxpositivo:    CMP   BX,0C00h          ;     └>     ├──────┤<-- pág 0
  1443.                JB    ems_busca_i       ; no distan 32 Kb: buscar otra
  1444. emm_obt_kb:    MOV   AH,42h
  1445.                INT   67h
  1446.                AND   AH,AH
  1447.                JZ    emm_kb_ok
  1448.                CMP   AH,82h
  1449.                JE    emm_obt_kb
  1450.                JMP   emm_fatal
  1451. emm_kb_ok:     MOV   CL,4
  1452.                SHL   BX,CL             ; páginas EMS disponibles
  1453.                MOV   ems_kb,BX         ; Kb EMS disponibles (0,16,...)
  1454. ems_ok:        POP   ES
  1455.                RET
  1456. eval_ems       ENDP
  1457.  
  1458. emm_busca_pag  PROC                    ; buscar página nº DX (EMS 4.0)
  1459.                LEA   SI,area_trabajo
  1460.                PUSH  CX
  1461. emm_otra_pag:  LODSW
  1462.                MOV   BX,AX             ; BX = segmento de la página
  1463.                LODSW                   ; AX = nº de la página
  1464.                CMP   AX,DX
  1465.                JE    hallada_pag
  1466.                LOOP  emm_otra_pag
  1467.                STC
  1468. hallada_pag:   POP   CX
  1469.                RET
  1470. emm_busca_pag  ENDP
  1471.  
  1472.                ; ---- Calcular el tamaño del mayor bloque de memoria
  1473.                ;      convencional disponible. Como mínimo se dejarán
  1474.                ;      unos 128 Kb libres en él, para que el usuario
  1475.                ;      pueda volver a ejecutar TDSK y el DOS tenga algo
  1476.                ;      de memoria libre. A la mitad de esos 128Kb (para
  1477.                ;      evitar solapamientos) es donde TURBODSK se
  1478.                ;      autorelocalizará antes de formatear el disco.
  1479.  
  1480. eval_con       PROC
  1481.                CMP   modo,AUTOEXEC     ; ¿se ejecuta desde el DOS?
  1482.                JNE   conv_ok           ; no, desde el config
  1483.                MOV   AH,48h
  1484.                MOV   BX,0FFFFh         ; pedir 1 Mb al DOS (fallará)
  1485.                INT   21h
  1486.                MOV   DX,BX             ; tamaño del mayor bloque
  1487.                MOV   CL,6
  1488.                SHR   BX,CL             ; BX = Kb del mayor bloque
  1489.                SUB   BX,128            ; restar 128 Kb
  1490.                JC    conv_ok           ; no quedan ni 128 Kb
  1491.                CMP   BX,8
  1492.                JB    conv_ok           ; no quedan siquiera 8 Kb
  1493.                MOV   con_kb,BX
  1494.                MOV   BX,DX             ; tamaño del mayor bloque
  1495.                MOV   AH,48h
  1496.                PUSH  BX
  1497.                INT   21h               ; localizarlo (AX=segmento)
  1498.                POP   BX
  1499.                XPUSH <ES,AX>           ; preservar ES y segmento (AX)
  1500.                ADD   AX,BX             ; añadir longitud
  1501.                SUB   AX,1024/16*64     ; restar 64 Kb
  1502.                MOV   segm_reubicar,AX  ; segmento de autoreubicación
  1503.                POP   ES                ; recuperar segmento del bloque
  1504.                MOV   AH,49h
  1505.                INT   21h               ; liberarlo
  1506.                POP   ES                ; recuperar ES
  1507. conv_ok:       RET
  1508. eval_con       ENDP
  1509.  
  1510. ; ------------ Reservar la memoria llamando al gestor que la controla.
  1511. ;              Con memoria XMS y existiendo un controlador EMS 4.0+ se
  1512. ;              comprueba si el handle XMS provoca la creacción de otro
  1513. ;              en EMS (caso de QEMM386 y otros emuladores de EMS) y en
  1514. ;              ese caso se le renombra, para mejorar la información de
  1515. ;              los programas de diagnóstico.
  1516.  
  1517. mem_reserva    PROC
  1518.                MOV   AL,tipo_soporte   ; tipo de memoria empleada
  1519.                DEC   AL
  1520.                JZ    mem_r_xms         ; 1: memoria extendida XMS
  1521.                DEC   AL
  1522.                JZ    mem_r_ems         ; 2: memoria expandida EMS
  1523.                MOV   CL,6
  1524.                MOV   BX,tdisco         ; 3: memoria convencional
  1525.                SHL   BX,CL
  1526.                MOV   AH,48h
  1527.                INT   21h
  1528.                MOV   mem_handle,AX     ; segmento del disco virtual
  1529.                MOV   BX,segm_psp
  1530.                MOV   tdsk_psp,BX       ; inicializar esta variable
  1531.                RET
  1532. mem_r_xms:     CMP   ems4,ON
  1533.                JNE   skip_lst_hndl
  1534.                LEA   BX,area_trabajo
  1535.                CALL  lista_handles     ; EMS 4.0+: listado de handles
  1536. skip_lst_hndl: MOV   AH,9
  1537.                MOV   DX,tdisco
  1538.                CALL  xms_driver        ; pedir memoria XMS
  1539.                AND   AX,AX
  1540.                JNZ   mem_rda_xms
  1541.                OR    lista_err,ERROR8  ; fallo del controlador XMS
  1542.                STC                     ; indicar error
  1543. mem_rda_xms:   MOV   mem_handle,DX
  1544.                PUSHF                   ; preservar condición de error
  1545.                CMP   ems4,ON
  1546.                JNE   skip_ren_hndl
  1547.                CALL  ren_handle        ; en EMS 4.0+ renombrar handle
  1548. skip_ren_hndl: POPF
  1549.                RET
  1550. mem_r_ems:     MOV   BX,tdisco
  1551.                ADD   BX,15
  1552.                AND   BL,11110000b      ; redondear para arriba
  1553.                MOV   tdisco,BX
  1554.                MOV   CL,4
  1555.                SHR   BX,CL             ; Kb -> nº páginas de 16 Kb
  1556.                MOV   AH,43h
  1557.                INT   67h               ; pedir memoria EMS
  1558.                AND   AH,AH
  1559.                JZ    mem_rda_ems
  1560.                OR    lista_err,ERROR9  ; fallo del controlador EMS
  1561.                STC                     ; indicar error
  1562.                RET
  1563. mem_rda_ems:   MOV   mem_handle,DX
  1564.                CMP   ems4,ON
  1565.                JNE   nhandle_ok
  1566.                CALL  nombrar_hndl      ; en EMS 4.0+ nombrar handle
  1567. nhandle_ok:    CLC
  1568.                RET
  1569. mem_reserva    ENDP
  1570.  
  1571. ren_handle     PROC                    ; detectar el handle EMS ligado
  1572.                XPUSH <ES,DS>           ; al handle XMS y renombrarlo
  1573.                POP   ES
  1574.                LEA   BX,area_trabajo[512]
  1575.                CALL  lista_handles     ; crear nueva lista de handles
  1576.                LEA   SI,area_trabajo
  1577.                LEA   DI,area_trabajo[512]
  1578.                MOV   CX,256
  1579.                CLD
  1580.                REP   CMPSW             ; comparar con vieja lista
  1581.                JE    ren_hnld_fin
  1582.                MOV   DX,[DI-2]         ; handle nuevo
  1583.                CALL  nombrar_hndl
  1584. ren_hnld_fin:  POP   ES
  1585.                RET
  1586. ren_handle     ENDP
  1587.  
  1588. lista_handles  PROC                    ; crear en DS:BX una lista con
  1589.                MOV   CX,256            ; los 256 posibles handles
  1590.                XOR   DX,DX             ; activos indicando los usados
  1591. listar_h:      MOV   AX,5300h
  1592.                LEA   DI,area_trabajo[tam_a_trabajo-8]  ; zona no usada
  1593.                XPUSH <BX,CX,DX>
  1594.                INT   67h
  1595.                XPOP  <DX,CX,BX>
  1596.                CMP   AH,0
  1597.                JE    handle_usado
  1598.                MOV   WORD PTR [BX],0   ; error (handle no usado)
  1599.                JMP   lista_h
  1600. handle_usado:  MOV   [BX],DX           ; anotar número de handle
  1601. lista_h:       ADD   BX,2
  1602.                INC   DX
  1603.                LOOP  listar_h
  1604.                RET
  1605. lista_handles  ENDP
  1606.  
  1607. nombrar_hndl   PROC                    ; nombrar handle (EMS 4.0+)
  1608.                MOV   AX,5301h
  1609.                LEA   SI,nombre_tdsk
  1610.                MOV   BL,letra_unidad
  1611.                MOV   [SI+5],BL
  1612.                INT   67h               ; dar nombre al handle
  1613.                RET
  1614. nombrar_hndl   ENDP
  1615.  
  1616. ; ------------ Detectar 286 y 386 o superior.
  1617.  
  1618. test_CPU       PROC
  1619.                PUSHF
  1620.                POP   AX
  1621.                OR    AH,70h        ; intentar activar bit 12, 13 ó 14
  1622.                PUSH  AX            ; del registro de estado
  1623.                POPF
  1624.                PUSHF
  1625.                POP   AX
  1626.                AND   AH,0F0h
  1627.                CMP   AH,0F0h
  1628.                JE    fin_test_CPU  ; es 8086 o similar
  1629.                MOV   cpu286,ON     ; es 286 o superior
  1630.                AND   AH,70h        ; 286 pone bits 12, 13 y 14 a cero
  1631.                JZ    fin_test_CPU  ; es 286
  1632.                MOV   cpu386,ON     ; 386 o superior
  1633. fin_test_CPU:  RET
  1634. test_CPU       ENDP
  1635.  
  1636. ; ------------ Definir valores por defecto y adaptar los parámetros
  1637. ;              indicados por el usuario a la realidad. Esta rutina
  1638. ;              inicializa el futuro sector 0 del disco. No se permite
  1639. ;              que el usuario indique un directorio que ocupe más de
  1640. ;              medio disco. Para determinar el tipo de FAT se halla el
  1641. ;              nº de sectores libres del disco (llamémoslo nsect),
  1642. ;              descontanto el sector de arranque y el directorio raiz;
  1643. ;              y se aplica la siguiente fórmula, que devuelve el nº de
  1644. ;              cluster más alto del disco al considerar también la
  1645. ;              ocupación de la futura FAT (12 bits = 1,5 bytes):
  1646. ;
  1647. ;                 nsect * tamsect          2 * nsect * tamsect
  1648. ;                ------------------ + 1 = --------------------- + 1
  1649. ;                 tamcluster + 1,5         2 * tamcluster + 3
  1650. ;
  1651. ;                Al resultado se le suma 1, ya que los clusters se
  1652. ;              numeran a partir de 2, para calcular el cluster de nº
  1653. ;              más alto del disco. Si ese número es 4086 o más habrá
  1654. ;              de utilizarse una FAT de 16 bits, recalculándose la
  1655. ;              fórmula anterior sustituyendo 1,5 por 2 y 3 por 4. Al
  1656. ;              final, una vez determinado el tipo de FAT habrá de
  1657. ;              calcularse con exactitud el número de cluster más alto,
  1658. ;              ya que hay casos críticos en que una FAT12 no sirve
  1659. ;              pero al aplicar una FAT16 el número de clusters baja de
  1660. ;              nuevo de 4085 (debido al mayor consumo de disco de la
  1661. ;              FAT16) resultado de ello la asignación de una FAT12,
  1662. ;              pese a que se reserva espacio para la de 16. Hay que
  1663. ;              considerar además el caso de que el disco tenga 2 FAT.
  1664.  
  1665. adaptar_param  PROC
  1666.                MOV   AX,tdisco     ; en Kb
  1667.                MOV   BX,AX         ; entradas de directorio propuestas
  1668.                MOV   CL,1          ; sectores por cluster propuestos
  1669.                CMP   AX,128        ; ¿disco de 128 Kb o menos?
  1670.                JBE   prop_ok
  1671.                MOV   BX,128
  1672.                CMP   AX,512        ; ¿disco de 512 Kb o menos?
  1673.                JBE   prop_ok
  1674.                MOV   BX,256
  1675.                CMP   AX,2042       ; ¿disco de casi 2 Mb o menos?
  1676.                JBE   prop_ok
  1677.                MOV   CL,2          ; evitar FAT16
  1678.                CMP   AX,4084       ; ¿disco de casi 4 Mb o menos?
  1679.                JBE   prop_ok
  1680.                MOV   CL,4          ; evitar FAT16 hasta 8 Mb
  1681.                MOV   BX,384
  1682.                CMP   AX,16384      ; ¿disco de menos de 16 Mb?
  1683.                JB    prop_ok
  1684.                MOV   BX,512
  1685. prop_ok:       CMP   dosver,300h
  1686.                JAE   prop_valido
  1687.                CMP   AX,4084*2     ; en DOS 2.xx evitar FAT16
  1688.                JB    prop_valido
  1689.                MOV   CL,8
  1690.                CMP   AX,4084*4
  1691.                JB    prop_valido
  1692.                MOV   CL,16
  1693.                CMP   AX,4084*8
  1694.                JB    prop_valido
  1695.                MOV   CL,32
  1696. prop_valido:   MOV   tdir,BX
  1697.                MOV   tcluster,CL   ; inicializar valores recomendados
  1698.                MOV   DX,1024       ; AX = tamaño del disco en Kb
  1699.                MUL   DX            ; DX:AX = bytes totales del disco
  1700.                MOV   CX,param_tsect
  1701.                AND   CX,CX
  1702.                JNZ   tsect_def     ; se ha definido tamaño de sector
  1703. tsect_rec:     MOV   CX,tsect      ; tamaño por defecto
  1704. tsect_def:     CALL  divCX
  1705.                JNC   nsect_ok      ; menos de 65536 sectores: correcto
  1706.                OR    lista_err,ERROR11
  1707.                JMP   tsect_rec     ; asumir por defecto y recalcular
  1708. nsect_ok:      MOV   tsect,CX
  1709.                MOV   numsect,AX
  1710.                MOV   BX,AX
  1711.                SHR   BX,1          ; BX = 1/2 del nº total de sectores
  1712.                MOV   CX,param_tdir
  1713.                AND   CX,CX
  1714.                JNZ   tdir_def      ; se ha definido nº entradas
  1715. tdir_rec:      MOV   CX,tdir       ; nº por defecto
  1716. tdir_def:      MOV   AX,tsect
  1717.                XOR   DX,DX
  1718.                MOV   SI,32         ; 32 bytes = tamaño entrada direct.
  1719.                DIV   SI            ; AX nº entradas direct. por sector
  1720.                XCHG  AX,CX
  1721.                XOR   DX,DX         ; DX:AX = nº de entradas
  1722.                DIV   CX            ; CX = entradas en cada sector
  1723.                AND   DX,DX         ; AX = nº sectores del ROOT
  1724.                JZ    dir_ok?
  1725.                INC   AX            ; redondear tamaño de ROOT
  1726. dir_ok?:       CMP   AX,BX         ; BX = 1/2 nº sectores del disco
  1727.                JB    dir_ok
  1728.                OR    lista_err,ERROR12  ; directorio excesivo
  1729.                JMP   tdir_rec      ; directorio por defecto
  1730. dir_ok:        MOV   sdir,AX
  1731.                MUL   tsect
  1732.                MOV   CX,32
  1733.                CALL  divCX
  1734.                MOV   tdir,AX       ; optimizar tamaño de directorio
  1735.                MOV   AX,512
  1736.                XOR   DX,DX
  1737.                DIV   tsect         ; 512 / tamaño de sector
  1738.                MOV   BL,tcluster
  1739.                XOR   BH,BH
  1740.                MUL   BX            ; ajustar tamaño de cluster
  1741.                AND   AL,AL
  1742.                JZ    propclus_ok
  1743.                MOV   tcluster,AL
  1744. propclus_ok:   MOV   BX,param_tcluster
  1745.                AND   BX,BX
  1746.                JNZ   tcluster_def  ; se ha definido tamaño de cluster
  1747. tcluster_rec:  MOV   BL,tcluster   ; tamaño por defecto
  1748.                XOR   BH,BH
  1749. tcluster_def:  SHL   BX,1
  1750.                CMP   BX,numsect    ; ¿cabe seguro un cluster?
  1751.                JB    tcluster_ok
  1752. tcluster_mal:  OR    lista_err,ERROR13 ; tamaño de cluster incorrecto
  1753.                JMP   tcluster_rec
  1754. tcluster_ok:   SHR   BX,1
  1755.                MOV   AX,tsect
  1756.                MUL   BX            ; DX:AX = tamaño de cluster
  1757.                JC    tcluster_mal
  1758.                CMP   AX,31*1024
  1759.                JA    tcluster_mal  ; cluster de más de 31 Kb
  1760.                MOV   tcluster,BL   ; sectores por cluster
  1761.                MOV   tamcluster,AX ; tamaño de cluster
  1762.                MOV   CX,param_f    ; considerar número de FATs
  1763.                MOV   nfats,CL
  1764.                MOV   SI,3
  1765.                MOV   CX,param_f
  1766.                SHL   SI,CL
  1767.                SHR   SI,1
  1768.                CALL  eval_clust    ; obtener nº más alto de cluster
  1769.                CMP   AX,4086
  1770.                JAE   fat16         ; el nº más alto supera 4085
  1771.                MOV   CX,3
  1772.                MUL   CX            ; clusters * 3
  1773.                SHR   DX,1
  1774.                RCR   AX,1          ; clusters * 3 / 2 = clusters * 1,5
  1775.                JMP   calc_sfat
  1776. fat16:         MOV   SI,4
  1777.                MOV   CX,param_f    ; considerar número de FATs
  1778.                SHL   SI,CL
  1779.                SHR   SI,1
  1780.                CALL  eval_clust
  1781.                SHL   AX,1
  1782.                RCL   DX,1          ; clusters * 2
  1783. calc_sfat:     DIV   tsect         ; AX = nº sectores de FAT aprox.
  1784.                AND   DX,DX
  1785.                JZ    fat_ok
  1786.                INC   AX            ; redondeo
  1787. fat_ok:        MOV   sfat,AX
  1788.                MOV   AX,numsect    ; nº total de sectores
  1789.                DEC   AX            ; descontar BOOT
  1790.                SUB   AX,sdir       ; descontar ROOT
  1791.                SUB   AX,sfat       ; descontar FAT
  1792.                MOV   CL,tcluster
  1793.                XOR   CH,CH
  1794.                XOR   DX,DX
  1795.                DIV   CX            ; AX = número real de clusters
  1796.                INC   AX            ; se numeran desde 2
  1797.                MOV   ultclus,AX
  1798.                RET
  1799. adaptar_param  ENDP
  1800.  
  1801. eval_clust     PROC                ; obtener el nº más alto de cluster
  1802.                MOV   AX,numsect
  1803.                DEC   AX            ; restar BOOT
  1804.                SUB   AX,sdir       ; restar ROOT
  1805.                MUL   tsect         ; DX:AX = nsect * tamsect
  1806.                SHL   AX,1
  1807.                RCL   DX,1          ; DX:AX = nsect * tamsect * 2
  1808.                MOV   CX,tamcluster
  1809.                SHL   CX,1
  1810.                ADD   CX,SI         ; CX = 2 * tamcluster + SI
  1811.                DIV   CX
  1812.                INC   AX            ; los clusters se numeran desde 2
  1813.                AND   DX,DX         ; ¿sobra un «cacho» de cluster?
  1814.                JZ    clust_eval    ; redondear: ¡es preferible que
  1815.                INC   AX            ; sobre un poco de FAT a que falte!
  1816. clust_eval:    XOR   DX,DX         ; resultado en DX:AX
  1817.                RET
  1818. eval_clust     ENDP
  1819.  
  1820. ; ------------ Preparar el BPB del disco virtual según los parámetros
  1821. ;              y forzar que el DOS lo lea indicando cambio de disco.
  1822.  
  1823. preparar_BPB   PROC
  1824.                MOV   AX,tsect
  1825.                MOV   bytes_sector,AX
  1826.                MOV   AL,tcluster
  1827.                MOV   sect_cluster,AL
  1828.                MOV   AX,tdir
  1829.                MOV   entradas_raiz,AX
  1830.                MOV   AX,numsect
  1831.                MOV   num_sect,AX
  1832.                MOV   AL,nfats
  1833.                MOV   num_fats,AL
  1834.                MOV   AX,sfat
  1835.                MOV   sectores_fat,AX
  1836.                MOV   cambiado,0FFh     ; ha habido «cambio» de disco
  1837.                RET
  1838. preparar_BPB   ENDP
  1839.  
  1840. ; ------------ Preparar el disco para operar. ES apunta al disco al
  1841. ;              entrar. Se procederá a copiar la rutina necesaria en
  1842. ;              función del tipo de memoria que gestiona el disco.
  1843. ;              Después, se copiarán las variables que gestionan TDSK
  1844. ;              sobre la copia residente, así como el nuevo BPB.
  1845.  
  1846. prep_driver    PROC
  1847.                MOV   AL,tipo_soporte
  1848.                LEA   SI,procesa_xms
  1849.                MOV   CX,tam_proc_xms
  1850.                DEC   AL
  1851.                JZ    prep_mem          ; instalar rutina XMS
  1852.                LEA   SI,procesa_ems
  1853.                MOV   CX,tam_proc_ems
  1854.                DEC   AL
  1855.                JZ    prep_mem          ; instalar rutina EMS
  1856.                LEA   SI,procesa_con
  1857.                MOV   CX,tam_proc_con   ; instalar rutina memoria conv.
  1858. prep_mem:      LEA   DI,procesa_io
  1859.                CLD
  1860.                XPUSH <SI,DI,CX>
  1861.                REP   MOVSB             ; instalar rutina en el disco
  1862.                XPOP  <CX,DI,SI>
  1863.                XPUSH <ES,DS>
  1864.                POP   ES
  1865.                REP   MOVSB             ; y en el propio TDSK.EXE (para
  1866.                POP   ES                ; usarla después al formatear)
  1867.                LEA   CX,f_tdsk_ctrl
  1868.                LEA   SI,i_tdsk_ctrl
  1869.                SUB   CX,SI
  1870.                MOV   DI,SI
  1871.                REP   MOVSB             ; actualizar variables
  1872.                LEA   CX,fin_bpb
  1873.                LEA   SI,bpb
  1874.                SUB   CX,SI
  1875.                MOV   DI,SI
  1876.                REP   MOVSB             ; actualizar BPB
  1877.                RET
  1878. prep_driver    ENDP
  1879.  
  1880. ; ------------ Autorelocalización de TDSK.EXE
  1881. ;              Es necesario si se reserva memoria convencional para el
  1882. ;              disco virtual. El motivo es evitar que al inicializar
  1883. ;              la BOOT, la FAT y el ROOT al inicio del disco, si éste
  1884. ;              está justo encima de TDSK, TDSK se autodestruya. Por
  1885. ;              ello, TDSK se autocopiará en la mitad de los 128 Kb del
  1886. ;              mayor bloque de memoria libre, nunca utilizados por el
  1887. ;              disco (aunque este bloque no haya sido reservado, ¡como
  1888. ;              está libre!). Finalmente pasará a correr en ese nuevo
  1889. ;              destino. Se copia TODO, pila incluida. La copia se hace
  1890. ;              en «segm_reubicar» que apunta a la mitad de esos 128 Kb
  1891. ;              con objeto de evitar solapamientos origen/destino (TDSK
  1892. ;              ocupa sólo alrededor de 16 Kb en memoria).
  1893.  
  1894. relocalizar    PROC
  1895.                CMP   tipo_soporte,3
  1896.                JE    procede_reloc     ; usada memoria convencional
  1897.                RET
  1898. procede_reloc: PUSH  ES                ; * preservar ES
  1899.                MOV   ES,segm_reubicar  ; segmento de reubicación
  1900.                XOR   SI,SI
  1901.                XOR   DI,DI
  1902.                MOV   BX,SS             ; final de TURBODSK (pila)
  1903.                MOV   CX,DS             ; inicio de _PRINCIPAL
  1904.                SUB   BX,CX             ; tamaño de TDSK en párrafos
  1905.                MOV   CL,4
  1906.                SHL   BX,CL             ; ahora en bytes
  1907.                ADD   BX,tam_pila+16    ; 16 por si acaso
  1908.                MOV   CX,BX             ; CX = bytes a relocalizar
  1909.                CLD
  1910.                REP   MOVSB             ; auto-copiaje arriba
  1911.                MOV   AX,ES
  1912.                MOV   DS,AX             ; nuevo segmento de datos
  1913.                POP   ES                ; * restaurar ES
  1914.                MOV   BX,CS
  1915.                SUB   AX,BX             ; ES - CS --> cuantía del salto
  1916.                MOV   BX,SS
  1917.                ADD   BX,AX
  1918.                MOV   SS,BX             ; actualizar segmento de pila
  1919.                POP   AX                ; dirección de retorno cercano
  1920.                PUSH  DS                ; segmento de «retorno»
  1921.                PUSH  AX                ; offset
  1922.                RETF                    ; retorno cargando CS:
  1923. relocalizar    ENDP
  1924.  
  1925. ; ------------ Inicializar la BOOT, FAT y ROOT del disco virtual.
  1926. ;              En versiones del DOS anteriores a la 3.3, el sistema
  1927. ;              inexplicablemente hace caso omiso del cambio de disco
  1928. ;              (¿?), por lo que hay que avisarle ¡dos veces!, con el
  1929. ;              correspondiente doble cambio del byte descriptor de
  1930. ;              medio, para que se tome en serio el cambio de disco.
  1931. ;              Por fortuna desde el DOS 3.3 ya no es preciso hacer
  1932. ;              esta extraña maniobra. Para que el DOS acceda al disco,
  1933. ;              se le pregunta simplemente el espacio libre del mismo.
  1934.  
  1935. formatear_tdsk PROC
  1936.                PUSH  ES                ; *
  1937.                PUSH  DS
  1938.                POP   ES
  1939.                LEA   SI,sector_cero
  1940.                LEA   DI,area_trabajo
  1941.                MOV   CX,128
  1942.                CLD
  1943.                REP   MOVSB             ; primeros 128 bytes del BOOT
  1944.                XOR   AX,AX
  1945.                MOV   CX,tam_a_trabajo-128
  1946.                REP   STOSB             ; a 0 resto del área de trabajo
  1947.                LEA   DI,area_trabajo
  1948.                ADD   DI,tsect
  1949.                MOV   [DI-2],0AA55h     ; marca de sector válido
  1950.                CALL  escribe_sectAX    ; escribir sector BOOT (AX=0)
  1951.                LEA   DI,area_trabajo
  1952.                MOV   CX,tsect
  1953.                REP   STOSB             ; borrar area de trabajo
  1954.                MOV   AX,sfat
  1955.                MOV   CX,param_f        ; considerar número de FATs
  1956.                SHL   AX,CL
  1957.                SHR   AX,1
  1958.                ADD   AX,sdir           ; AX = sectores fat + dir. raiz
  1959. ini_fat:       CMP   AX,1
  1960.                JE    pfat
  1961.                CALL  escribe_sectAX    ; inicializar directorio raiz
  1962.                DEC   AX                ; y últimos sectores de la FAT
  1963.                JMP   ini_fat
  1964. pfat:          LEA   DI,area_trabajo
  1965.                MOV   BYTE PTR [DI],media
  1966.                MOV   AX,0FFFFh         ; inicializar 3 bytes FAT...
  1967.                MOV   DS:[DI+1],AX
  1968.                CMP   ultclus,4086      ; ¿menos de 4085 clusters?
  1969.                JB    pfat_ok
  1970.                MOV   DS:[DI+3],AL      ; inicializar 4º byte FAT
  1971. pfat_ok:       MOV   AX,1
  1972.                CALL  escribe_sectAX    ; primer sector FAT preparado
  1973.                CALL  fecha_hora
  1974.                LEA   SI,dir_raiz
  1975.                MOV   [SI+22],AX        ; hora actual
  1976.                MOV   [SI+24],DX        ; fecha actual
  1977.                LEA   DI,area_trabajo
  1978.                MOV   CX,32
  1979.                REP   MOVSB
  1980.                MOV   AX,sfat
  1981.                MOV   CX,param_f        ; considerar número de FATs
  1982.                SHL   AX,CL
  1983.                SHR   AX,1
  1984.                INC   AX
  1985.                CALL  escribe_sectAX    ; primer sector raiz preparado
  1986.                POP   ES                ; *
  1987.                CMP   dosver,31Eh
  1988.                JAE   formateado        ; DOS 3.3+
  1989.                NOT   ES:media_byte     ; cambiar descriptor de medio
  1990.                MOV   AH,36h            ; «obtener espacio libre»
  1991.                MOV   DL,ES:letra_unidad
  1992.                SUB   DL,'A'-1          ; unidad de disco virtual
  1993.                PUSH  DX
  1994.                INT   21h               ; primer acceso al disco
  1995.                POP   DX
  1996.                NOT   ES:media_byte     ; restaurar descriptor de medio
  1997.                MOV   ES:cambiado,0FFh  ; nuevo «cambio» de disco
  1998.                MOV   AH,36h
  1999.                INT   21h               ; acceder otra vez al disco
  2000. formateado:    RET
  2001. formatear_tdsk ENDP
  2002.  
  2003.                ; ---- Escribir el sector nº AX del disco virtual. No
  2004.                ;      se utiliza INT 26h (imposible desde el CONFIG).
  2005.  
  2006. escribe_sectAX PROC
  2007.                PUSHF                   ; preservar bit DF
  2008.                XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
  2009.                XOR   BP,BP             ; indicar escritura
  2010.                LEA   DI,area_trabajo   ; ES:DI buffer
  2011.                MOV   BX,AX             ; número de sector
  2012.                MOV   AX,1              ; 1 sector
  2013.                CALL  io_proc           ; acceder al disco directamente
  2014.                XPOP  <ES,DS,BP,DI,SI,DX,CX,BX,AX>
  2015.                POPF
  2016.                RET
  2017. escribe_sectAX ENDP
  2018.  
  2019.                ; ---- Obtener fecha y hora del sistema en DX y AX
  2020.  
  2021. fecha_hora     PROC
  2022.                MOV   AH,2Ah
  2023.                INT   21h               ; obtener fecha del sistema
  2024.                MOV   AL,32
  2025.                MUL   DH                ; AX = mes * 32
  2026.                SUB   CX,1980
  2027.                SHL   CL,1              ; (año-1980)*2
  2028.                ADD   AH,CL             ; sumar (año-1980)*512
  2029.                MOV   CL,DL             ; CX = dia (CH=0)
  2030.                ADD   AX,CX
  2031.                PUSH  AX                ; * guardar fecha
  2032.                MOV   AH,2Ch
  2033.                INT   21h               ; obtener hora del sistema
  2034.                MOV   AL,32
  2035.                MUL   CL                ; AX = minutos*32
  2036.                MOV   CL,3
  2037.                SHL   CH,CL
  2038.                XOR   CL,CL             ; CX = hora*2048
  2039.                ADD   AX,CX
  2040.                SHR   DH,1              ; segundos/2
  2041.                ADD   AL,DH
  2042.                ADC   AH,0
  2043.                POP   DX                ; * recuperar fecha
  2044.                RET
  2045. fecha_hora     ENDP
  2046.  
  2047. ; ------------ Cambiar el nombre al bloque de control de memoria para
  2048. ;              mejorar la información del comando MEM del sistema si
  2049. ;              el disco se define en memoria convencional/superior.
  2050.  
  2051. renombrar_mcb  PROC
  2052.                PUSH  ES
  2053.                MOV   AL,letra_unidad
  2054.                MOV   BYTE PTR nombre_tdsk+5,AL
  2055.                MOV   BYTE PTR nombre_tdsk+4,'('
  2056.                MOV   BYTE PTR nombre_tdsk+6,')'
  2057.                MOV   AX,segm_psp
  2058.                DEC   AX
  2059.                MOV   ES,AX
  2060.                LEA   SI,nombre_tdsk
  2061.                MOV   DI,8
  2062.                MOV   CX,DI
  2063.                CLD
  2064.                REP   MOVSB
  2065.                POP   ES
  2066.                RET
  2067. renombrar_mcb  ENDP
  2068.  
  2069. ; ------------ Informar sobre el disco virtual instalado.
  2070.  
  2071. info_disco     PROC
  2072.                CALL  InitMultiPrint
  2073.                CALL  habla_hispana?
  2074.                LEA   DX,ayuda_txt      ; ayuda en español
  2075.                CMP   idioma_sp,ON
  2076.                JE    info_ayuda_ok
  2077.                LEA   DX,ayuda_ex_txt   ; ayuda en inglés
  2078. info_ayuda_ok: CMP   param_h,ON        ; ¿solicitud de ayuda?
  2079.                JNE   cont_info         ; no
  2080.                JMP   info_exit
  2081. cont_info:     TEST  err_grave,0FFFFh
  2082.                JZ    info_no_fatal
  2083.                LEA   DX,err_grave_gen  ; texto de encabezamiento
  2084.                CALL  imprimir          ; imprimir errores graves:
  2085.                LEA   DX,e0             ; en español
  2086.                CMP   idioma_sp,ON
  2087.                JE    e0_ok
  2088.                LEA   DX,e0_ex          ; en inglés
  2089. e0_ok:         TEST  err_grave,ERROR0
  2090.                JZ    otro_fallo        ; no es error de DOS incorrecto
  2091.                CALL  imprimir
  2092.                MOV   SP,tam_pila
  2093.                PUSH  segm_psp          ; en DOS 1.x hay que terminar
  2094.                XOR   AX,AX             ; con CS = PSP
  2095.                PUSH  AX
  2096.                RETF                    ; ejecutar INT 20h de PSP:0
  2097. otro_fallo:    LEA   AX,e1
  2098.                LEA   BX,e1_ex
  2099.                TEST  err_grave,ERROR1
  2100.                JNZ   info_g
  2101.                LEA   AX,e2
  2102.                LEA   BX,e2_ex
  2103.                TEST  err_grave,ERROR2
  2104.                JNZ   info_g
  2105.                LEA   AX,e3
  2106.                LEA   BX,e3_ex
  2107. info_g:        MOV   DX,AX             ; mensaje en español
  2108.                CMP   idioma_sp,ON
  2109.                JE    info_g_ok
  2110.                MOV   DX,BX             ; mensaje en inglés
  2111. info_g_ok:     JMP   info_exit
  2112. info_no_fatal: MOV   AL,letra_unidad   ; error no fatal
  2113.                MOV   inf_unidad1,AL
  2114.                MOV   inf_unidad1_,AL
  2115.                MOV   inf_unidad2,AL
  2116.                MOV   inf_unidad2_,AL   ; actualizadas letras de unidad
  2117.                CMP   ES:tipo_soporte,0
  2118.                JNE   info_reporte
  2119.                LEA   DX,info_ins       ; disco no formateado (español)
  2120.                CMP   idioma_sp,ON
  2121.                JE    info_ins_ok
  2122.                LEA   DX,info_ins_ex    ; disco no formateado (inglés)
  2123. info_ins_ok:   CMP   lista_err,0
  2124.                JE    info_exit         ; sin mensajes de advertencia
  2125.                CALL  imprimir          ; ... o con ellos
  2126.                JMP   info_err
  2127. info_reporte:  CALL  haz_info          ; disco formateado
  2128.                LEA   DX,info_txt       ; cuadro informativo en español
  2129.                CMP   idioma_sp,ON
  2130.                JE    info_txt_ok
  2131.                LEA   DX,info_txt_ex    ; cuadro informativo en inglés
  2132. info_txt_ok:   CMP   lista_err,0
  2133.                JE    info_exit         ; sin mensajes de advertencia
  2134.                CALL  imprimir          ; ... o con ellos
  2135.                LEA   DX,cab_adv_txt    ; cabecera en español
  2136.                CMP   idioma_sp,ON
  2137.                JE    cab_ok
  2138.                LEA   DX,cab_adv_ex_txt ; cabecera en inglés
  2139. cab_ok:        CALL  imprimir          ; cabecera de advertencias
  2140. info_err:      MOV   AX,lista_err
  2141.                LEA   BX,tabla_mens-2   ; tabla de mensajes en español
  2142.                CMP   idioma_sp,ON
  2143.                JE    tmens_ok
  2144.                LEA   BX,tabla_mens_ex-2  ; tabla de mensajes en inglés
  2145. tmens_ok:      MOV   CX,16             ; 16 posibles mensajes
  2146. busca_err:     ADD   BX,2
  2147.                SHR   AX,1
  2148.                JC    informa
  2149. mas_mens:      LOOP  busca_err         ; no se produce ese error
  2150.                JMP   info_ret
  2151. informa:       LEA   DX,mens_cabec     ; inicio común a los mensajes
  2152.                CALL  imprimir
  2153.                MOV   DX,[BX]           ; dirección de ese mensaje
  2154.                CALL  imprimir
  2155.                JMP   mas_mens          ; acabar con todos
  2156. info_exit:     CALL  imprimir
  2157. info_ret:      RET
  2158. info_disco     ENDP
  2159.  
  2160. haz_info       PROC
  2161.                MOV   AL,ES:tipo_soporte
  2162.                LEA   BX,inf_mem_xms
  2163.                LEA   CX,inf_mem_xms_ex
  2164.                DEC   AL
  2165.                JZ    mem_ifdo          ; memoria XMS
  2166.                LEA   BX,inf_mem_ems
  2167.                LEA   CX,inf_mem_ems_ex
  2168.                DEC   AL
  2169.                JZ    mem_ifdo          ; memoria EMS
  2170.                CMP   ES:mem_handle,0A000h
  2171.                JB    info_tsect        ; memoria convencional
  2172.                LEA   BX,inf_mem_sup    ; memoria superior
  2173.                LEA   CX,inf_mem_sup_ex
  2174. mem_ifdo:      MOV   SI,BX             ; mensaje en español
  2175.                LEA   DI,inf_mem
  2176.                CMP   idioma_sp,ON
  2177.                JE    mem_ifdo_ok
  2178.                MOV   SI,CX             ; mensaje en inglés
  2179.                LEA   DI,inf_mem_
  2180. mem_ifdo_ok:   MOV   CX,inf_mem_lon
  2181.                XPUSH <ES,DS>
  2182.                POP   ES
  2183.                CLD
  2184.                REP   MOVSB             ; indicar tipo de memoria
  2185.                POP   ES
  2186. info_tsect:    LEA   DI,inf_tsect
  2187.                LEA   SI,inf_tsect_
  2188.                MOV   AX,ES:bytes_sector
  2189.                CALL  haz_numero        ; indicar tamaño de sector
  2190.                LEA   DI,inf_tdir
  2191.                LEA   SI,inf_tdir_
  2192.                MOV   AX,ES:entradas_raiz
  2193.                CALL  haz_numero        ; indicar nº entradas direct.
  2194.                LEA   DI,inf_tdisco
  2195.                LEA   SI,inf_tdisco_
  2196.                MOV   AX,ES:num_sect
  2197.                MUL   ES:bytes_sector
  2198.                MOV   BX,1024
  2199.                DIV   BX
  2200.                CALL  haz_numero        ; indicar tamaño del disco
  2201.                LEA   DI,inf_tcluster
  2202.                LEA   SI,inf_tcluster_
  2203.                MOV   AL,ES:sect_cluster
  2204.                XOR   AH,AH
  2205.                CALL  haz_numero        ; indicar sectores por cluster
  2206.                MOV   AX,ES:entradas_raiz
  2207.                MOV   BX,32
  2208.                MUL   BX                ; bytes ocupados por directorio
  2209.                DIV   ES:bytes_sector   ; AX = sectores del directorio
  2210.                ADD   AX,ES:sect_reserv
  2211.                ADD   AX,ES:sectores_fat
  2212.                SUB   AX,ES:num_sect
  2213.                NEG   AX                ; AX = sectores libres
  2214.                XOR   DX,DX
  2215.                MOV   BL,ES:sect_cluster
  2216.                XOR   BH,BH
  2217.                DIV   BX                ; AX = nº de clusters
  2218.                CMP   AX,4085           ; ¿FAT12?
  2219.                JB    ifat_ok
  2220.                MOV   WORD PTR inf_tfat,"61"
  2221.                MOV   WORD PTR inf_tfat_,"61"
  2222. ifat_ok:       LEA   DI,inf_nclusters
  2223.                LEA   SI,inf_nclusters_
  2224.                CALL  haz_numero        ; indicar nº de clusters
  2225.                RET
  2226. haz_info       ENDP
  2227.  
  2228. haz_numero     PROC
  2229.                CMP   idioma_sp,ON
  2230.                JE    haz_idm_ok
  2231.                MOV   DI,SI             ; mensaje inglés y no español
  2232. haz_idm_ok:    MOV   BX,10000          ; empezar por decenas de millar
  2233.                MOV   CX,5              ; cinco dígitos
  2234. otro_dig:      PUSH  CX
  2235.                MOV   CL,-1
  2236. gen_digito:    INC   CL
  2237.                SUB   AX,BX
  2238.                JNC   gen_digito        ; se puede restar aún más
  2239.                ADD   AX,BX             ; deshacer desbordamiento
  2240.                ADD   CL,'0'            ; pasar a ASCII
  2241.                CMP   CL,'0'
  2242.                JNE   no_cero
  2243.                CMP   BYTE PTR [DI-1],' '  ; ¿anterior byte a cero?
  2244.                JNE   no_cero
  2245.                MOV   CL,' '            ; pues convertirlo en blanco
  2246. no_cero:       MOV   [DI],CL           ; dígito generado
  2247.                INC   DI                ; apuntar al siguiente
  2248.                XCHG  AX,BX
  2249.                MOV   CX,10
  2250.                XOR   DX,DX
  2251.                DIV   CX                ; pasar a otra potencia de 10
  2252.                XCHG  AX,BX
  2253.                POP   CX
  2254.                LOOP  otro_dig          ; acabar los dígitos
  2255.                RET
  2256. haz_numero     ENDP
  2257.  
  2258. ; ------------ Dividir DX:AX / CX sin desbordamientos (cociente: AX,
  2259. ;              resto: DX). Si el cociente excede los 16 bits, CF = 1
  2260. ;              y todos los registros intactos.
  2261.  
  2262. divCX          PROC
  2263.                XPUSH <BX,SI,CX,AX,DX>
  2264.                MOV   SI,32
  2265.                XOR   BX,BX
  2266. divmas:        SHL   AX,1
  2267.                RCL   DX,1
  2268.                RCL   BX,1
  2269.                CMP   BX,CX
  2270.                JB    dividido          ; "no cabe"
  2271.                SUB   BX,CX
  2272.                INC   AL                ; 1 al cociente
  2273. dividido:      DEC   SI
  2274.                JNZ   divmas
  2275.                AND   DX,DX
  2276.                JZ    div_ok
  2277.                XPOP  <DX,AX>           ; error
  2278.                STC
  2279.                JMP   div_fin
  2280. div_ok:        MOV   DX,BX             ; resto en DX y cociente en AX
  2281.                ADD   SP,4              ; «sacar» sin sacar DX y AX
  2282.                CLC
  2283. div_fin:       XPOP  <CX,SI,BX>        ; recuperar CX, SI y BX
  2284.                RET
  2285. divCX          ENDP
  2286.  
  2287. ; ------------ Inicializar variable idioma_sp según la lengua del país
  2288.  
  2289. habla_hispana? PROC
  2290.                MOV   idioma_sp,OFF     ; supuesto de habla no hispana
  2291.                MOV   AX,param_i
  2292.                AND   AX,AX
  2293.                JNZ   habla_ax          ; parámetro /I indicado
  2294.                CMP   dosver,200h
  2295.                JB    habla_ok
  2296.                LEA   DX,area_trabajo
  2297.                MOV   AX,3800h
  2298.                INT   21h               ; obtener información del pais
  2299.                CMP   dosver,20Bh
  2300.                JE    habla_ax          ; DOS 2.11: AX cód. telefónico
  2301.                CMP   dosver,300h
  2302.                JB    habla_ok          ; 2.x excepto 2.11: mala suerte
  2303.                MOV   AX,BX
  2304. habla_ax:      LEA   BX,paises_sp-2
  2305.                MOV   CX,numpaises_sp
  2306. habla_sp?:     ADD   BX,2
  2307.                CMP   AX,[BX]
  2308.                JE    habla_hispana
  2309.                LOOP  habla_sp?
  2310. habla_ok:      RET
  2311. habla_hispana: MOV    idioma_sp,ON     ; país de habla hispana
  2312.                RET
  2313. habla_hispana? ENDP
  2314.  
  2315. ; ------------ Impresión en color o monocroma (esta última
  2316. ;              redireccionable). Desde el CONFIG.SYS se imprime en
  2317. ;              monocromo para no llamar la atención, a menos que
  2318. ;              indiquen /M, al contrario que desde el DOS.
  2319.  
  2320. imprimir       PROC
  2321.                PUSH  AX
  2322.                MOV   AL,param_m
  2323.                CMP   modo,CONFIG       ; ¿en CONFIG.SYS?
  2324.                JNE   m_ok              ; no
  2325.                XOR   AL,ON             ; sí: /M opera al revés
  2326. m_ok:          MOV   pr_mono,AL
  2327.                CALL  MultiPrint
  2328.                POP   AX
  2329.                RET
  2330. imprimir       ENDP
  2331.  
  2332. ; ------------ Impresión en pantalla, en color o monocromo, usando el
  2333. ;              BIOS o el DOS respectivamente. Antes deberá ejecutarse
  2334. ;              InitMultiPrint para inicializar.   Al  hacer scroll se
  2335. ;              intenta respetar el posible  color  global  de  fondo.
  2336. ;              Con «pr_mono» en ON se solicita imprimir en monocromo.
  2337. ;
  2338. ;              - El texto a imprimir es apuntado por DS:DX.
  2339. ;              - Códigos de control soportados:
  2340. ;
  2341. ;                 0 -> final de cadena
  2342. ;                 1 -> el siguiente carácter indica el color (BIOS)
  2343. ;                 2 -> el siguiente carácter indica el nº de veces que
  2344. ;                      se imprimirá el que viene detrás
  2345. ;                 3 -> avanzar cursor a la derecha
  2346. ;                10 -> retorno de carro y salto de línea estilo UNIX
  2347.  
  2348. MultiPrint     PROC
  2349.                XPUSH <AX,BX,CX,DX,SI,DI,BP,DS,ES>
  2350.                PUSH  DS
  2351.                POP   ES
  2352.                PUSH  CS
  2353.                POP   DS
  2354.                LEA   AX,pr_AL_dos
  2355.                CMP   pr_mono,ON
  2356.                JE    pr_rut_ok
  2357.                LEA   AX,pr_AL_bios
  2358. pr_rut_ok:     MOV   pr_rut,AX         ; instalar rutina de impresión
  2359.                MOV   BX,DX
  2360. pr_otro:       MOV   AL,ES:[BX]
  2361.                PUSH  BX
  2362.                CMP   AL,' '
  2363.                JAE   pr_ASCII          ; no es un código de control
  2364.                AND   AL,AL
  2365.                JZ    pr_exit           ; código de control 0: final
  2366.                CMP   AL,1
  2367.                JE    pr_setcolor       ; código de control 1: color
  2368.                CMP   AL,2
  2369.                JE    pr_setveces       ; código de control 2: repetir
  2370. pr_ASCII:      CALL  pr_rut
  2371.                POP   BX
  2372.                INC   BX
  2373.                JMP   pr_otro
  2374. pr_setcolor:   MOV   AL,ES:[BX+1]
  2375.                MOV   pr_color,AL       ; actualizar color
  2376.                POP   BX
  2377.                ADD   BX,2
  2378.                JMP   pr_otro
  2379. pr_setveces:   MOV   AL,ES:[BX+1]
  2380.                MOV   pr_veces,AL       ; actualizar repeticiones
  2381.                POP   BX
  2382.                ADD   BX,2
  2383.                JMP   pr_otro
  2384. pr_exit:       XPOP  <BX,ES,DS,BP,DI,SI,DX,CX,BX,AX>
  2385.                RET
  2386. MultiPrint     ENDP
  2387.  
  2388. pr_AL_bios     PROC                    ; imprimir en color usando BIOS
  2389.                PUSH  AX
  2390.                MOV   AH,3
  2391.                MOV   BH,pr_pagina
  2392.                INT   10h               ; DX = coordenadas del cursor
  2393.                POP   AX
  2394.                CMP   AL,3
  2395.                JE    pr_derecha        ; código de control 3: avanzar
  2396.                CMP   AL,10
  2397.                JE    pr_crlf           ; código de control 10: CR & LF
  2398.                MOV   AH,9
  2399.                MOV   BH,pr_pagina
  2400.                MOV   BL,pr_color
  2401.                MOV   CL,pr_veces
  2402.                XOR   CH,CH
  2403.                PUSH  DX
  2404.                INT   10h               ; imprimir carácter
  2405.                POP   DX
  2406. pr_derecha:    ADD   DL,pr_veces
  2407.                MOV   pr_veces,1
  2408.                CMP   DL,pr_maxX
  2409.                JBE   pr_av
  2410. pr_crlf:       XOR   DL,DL             ; volver al inicio de línea
  2411.                INC   DH                ; salto a la siguiente
  2412.                CMP   DH,pr_maxY
  2413.                JBE   pr_av
  2414.                DEC   DH
  2415.                PUSH  DX                ; es preciso hacer scroll
  2416.                MOV   AX,601h
  2417.                MOV   BH,pr_colorb      ; color por defecto
  2418.                XOR   CX,CX
  2419.                MOV   DL,pr_maxX
  2420.                MOV   DH,pr_maxY
  2421.                INT   10h               ; hacer scroll usando BIOS
  2422.                POP   DX
  2423. pr_av:         MOV   BH,pr_pagina
  2424.                MOV   AH,2
  2425.                INT   10h               ; posicionar cursor
  2426.                RET                     ; retorno del procedimiento
  2427. pr_AL_bios     ENDP
  2428.  
  2429. pr_AL_dos      PROC                    ; imprimir usando DOS
  2430.                CMP   AL,3
  2431.                JNE   pr_no_der
  2432.                MOV   AL,' '            ; código de control 3: avanzar
  2433. pr_no_der:     CMP   AL,10
  2434.                JNE   pr_dos
  2435.                MOV   AL,13             ; código de control 10: CR & LF
  2436.                CALL  pr_dos            ; llamada "recursiva"
  2437.                MOV   AL,10
  2438. pr_dos:        MOV   CL,pr_veces
  2439.                XOR   CH,CH
  2440.                MOV   pr_veces,1
  2441.                MOV   DL,AL
  2442. pr_chr:        XPUSH <DX,CX>
  2443.                MOV   AH,2
  2444.                INT   21h               ; imprimir carácter
  2445.                XPOP  <CX,DX>
  2446.                LOOP  pr_chr
  2447.                RET
  2448. pr_AL_dos      ENDP
  2449.  
  2450. InitMultiPrint PROC
  2451.                XPUSH <AX,BX,CX,DX,BP,DS,ES>
  2452.                PUSH  CS
  2453.                POP   DS
  2454.                MOV   pr_veces,1
  2455.                MOV   pr_color,15       ; valores por defecto
  2456.                MOV   pr_mono,OFF
  2457. pr_i_80?:      MOV   AH,0Fh
  2458.                INT   10h
  2459.                CMP   AH,80             ; ¿80 ó más columnas?
  2460.                JAE   pr_i_video_ok     ; así es
  2461.                MOV   AX,3
  2462.                INT   10h               ; forzar modo de 80 columnas
  2463.                JMP   pr_i_80?
  2464. pr_i_video_ok: MOV   pr_maxX,AH        ; inicializar máxima coord. X
  2465.                MOV   pr_pagina,BH      ; inicializar página activa
  2466.                MOV   AX,40h
  2467.                MOV   ES,AX             ; ES: -> variables del BIOS
  2468.                MOV   AL,ES:[84h]       ; variable de nº líneas - 1
  2469.                CMP   AL,24             ; ¿el BIOS define la variable?
  2470.                JB    pr_i_maxy_ok      ; no
  2471.                MOV   pr_maxY,AL        ; inicializar máxima coord. Y
  2472. pr_i_maxy_ok:  MOV   AH,8              ; (BH = página)
  2473.                INT   10h               ; obtener color por defecto
  2474.                MOV   pr_colorb,AH
  2475.                XPOP  <ES,DS,BP,DX,CX,BX,AX>
  2476.                RET
  2477. InitMultiPrint ENDP
  2478.  
  2479. pr_pagina      DB    0       ; página de visualización activa
  2480. pr_veces       DB    1       ; veces que se imprime cada carácter
  2481. pr_color       DB    15      ; color BIOS para imprimir
  2482. pr_colorb      DB    ?       ; color por defecto en pantalla
  2483. pr_maxX        DB    80      ; máxima coordenada X en pantalla
  2484. pr_maxY        DB    24      ; máxima coordenada Y en pantalla
  2485. pr_mono        DB    OFF     ; a ON si imprimir en monocromo
  2486. pr_rut         DW    ?       ; apunta a pr_AL_bios / pr_AL_dos
  2487.  
  2488. ; ------------ Rutina de gestión de memoria XMS. Se copiará sobre
  2489. ;              la de memoria EMS si se utiliza memoria XMS.
  2490. ;              En esta rutina se emplea la pila para pasar los
  2491. ;              parámetros al controlador XMS.
  2492.  
  2493. procesa_xms    PROC
  2494.                MOV   DS,CS:mem_handle
  2495.                JNC   no_xmslib
  2496.                .286                    ; rutina ejecutada desde 286+
  2497.                PUSHA                   ; sistema reinicializando:
  2498.                MOV   AH,0Dh
  2499.                CALL  llama_XMS         ; desbloquear EMB (prudente)
  2500.                MOV   AH,0Ah
  2501.                CALL  llama_XMS         ; liberar EMB
  2502.                POPA
  2503.                .8086
  2504.                RET
  2505. no_xmslib:     DEC   BP                ; leer/escribir en el disco
  2506.                JNZ   xms_escribe
  2507.                PUSH  ES
  2508.                PUSH  DI                ; segmento:offset destino
  2509.                PUSH  BP                ; handle destino (BP=0)
  2510. xms_escribe:   PUSH  DX
  2511.                PUSH  AX                ; desplazamiento DX:AX
  2512.                PUSH  DS                ; handle fuente/destino
  2513.                JZ    xms_general
  2514.                INC   BP                ; hacer BP = 0
  2515.                PUSH  ES
  2516.                PUSH  DI                ; segmento:offset fuente
  2517.                PUSH  BP                ; handle fuente (BP=0)
  2518. xms_general:   SHL   CX,1              ; palabras -> bytes
  2519.                RCL   BP,1              ; BP era 0
  2520.                PUSH  BP                ; tamaño bloque (parte alta)
  2521.                PUSH  CX                ; tamaño bloque (parte baja)
  2522.                MOV   SI,SP
  2523.                PUSH  SS
  2524.                POP   DS                ; DS:SI apuntando a la pila
  2525.                MOV   AH,0Bh            ; función para mover EMB
  2526.                CALL  llama_XMS         ; mover EMB (DS no importa)
  2527.                ADD   SP,16             ; equilibrar pila
  2528.                CMP   AL,1              ; ¿falló el controlador?
  2529.                JE    xms_proc_ok
  2530.                MOV   AX,0C81h          ; anomalía general
  2531. xms_proc_ok:   XCHG  AH,AL             ; colocar resultado
  2532.                RET
  2533. procesa_xms    ENDP
  2534.  
  2535. llama_XMS      PROC
  2536.                MOV   DX,DS             ; handle en DS (si utilizado)
  2537.                CALL  CS:xms_driver     ; ejecutar función XMS
  2538.                RET
  2539. llama_XMS      ENDP
  2540.  
  2541. tam_proc_xms   EQU   $-OFFSET procesa_xms   ; tamaño de esta rutina
  2542.  
  2543. ; ------------ Rutina de gestión de memoria convencional. Se copiará
  2544. ;              sobre la de memoria EMS si se utiliza memoria conv.
  2545.  
  2546. procesa_con    PROC
  2547.                JC    con_exit          ; sistema inicializándose
  2548.                MOV   BX,16             ; bytes por párrafo
  2549.                DIV   BX                ; AX = segmento, DX = offset
  2550.                ADD   AX,CS:mem_handle  ; segmento de inicio datos
  2551.                MOV   DS,AX
  2552.                MOV   SI,DX             ; DS:SI inicio de datos
  2553.                DEC   BP                ; y ES:DI destino del buffer
  2554.                JZ    con_general       ; es lectura
  2555.                XCHG  SI,DI             ; escritura: intercambiar
  2556.                XPUSH <DS,ES>
  2557.                XPOP  <DS,ES>
  2558. con_general:   CLD
  2559.                CMP   CS:cpu386,ON
  2560.                JE    con_tr32bit
  2561.                REP   MOVSW
  2562.                JMP   con_tr_fin
  2563. con_tr32bit:   SHR   CX,1              ; nº palabras de 32 bit a mover
  2564.                JCXZ  con_trdo          ; evitar desgracia
  2565.                .386
  2566.                PUSHAD
  2567.                XOR   EAX,EAX           ; asegurar no violación
  2568.                DEC   AX                ; de segmento-64K
  2569.                AND   ECX,EAX           ; EAX = 0FFFFh
  2570.                AND   ESI,EAX
  2571.                AND   EDI,EAX
  2572.                REP   MOVSD             ; transferencia ultrarrápida
  2573. con_trdo:      POPAD                   ; POPAD falla en muchos 386
  2574.                NOP                     ; arreglar fallo de POPAD
  2575.                .8086
  2576. con_tr_fin:    MOV   AX,100h           ; todo fue bien, por supuesto
  2577. con_exit:      RET
  2578. procesa_con    ENDP
  2579.  
  2580. tam_proc_con   EQU   $-OFFSET procesa_con   ; tamaño de esta rutina
  2581.  
  2582.  
  2583. ; ************ Datos no residentes para la instalación
  2584.  
  2585. ON             EQU   1            ; constantes booleanas
  2586. OFF            EQU   0
  2587.  
  2588. CONFIG         EQU   1            ; TURBODSK ejecutado desde el CONFIG
  2589. AUTOEXEC       EQU   2            ; TURBODSK se ejecuta desde el DOS
  2590.  
  2591. emm_id         DB    "EMMXXXX0"   ; identificación del controlador EMS
  2592.  
  2593. nombre_tdsk    DB    "TDSK U: "   ; para nombrar handle EMS y el MCB
  2594.  
  2595. modo           DB    ?            ; CONFIG/AUTOEXEC
  2596. dosver         DW    ?            ; versión del DOS
  2597. top_ram        DW    0            ; segmento más alto de la RAM
  2598. segm_psp       DW    0            ; segmento del PSP
  2599. segm_tdsk      DW    0            ; segmento donde reside TURBODSK
  2600. segm_reubicar  DW    0            ; segmento donde reubicar TURBODSK
  2601. ems4           DB    OFF          ; a ON si EMS versión 4.0+
  2602. cpu286         DB    OFF          ; a ON si 286 ó superior
  2603. idioma_sp      DB    OFF          ; a ON si mensajes en español
  2604.  
  2605. param_unidad   DB    0            ; número de disco si indicada unidad
  2606. param_tdiscof  DB    OFF          ; a ON si se define tamaño de disco
  2607. param_tdisco   DW    0            ; tamaño de disco (si se define)
  2608. param_tsect    DW    0            ; tamaño de sector (si se define)
  2609. param_tdir     DW    0            ; número de entradas (si se define)
  2610. param_tcluster DW    0            ; tamaño de cluster (si se define)
  2611. param_a        DB    OFF          ; a ON si indicado parámetro /A o /X
  2612. param_e        DB    OFF          ; a ON si indicado parámetro /E
  2613. param_c        DB    OFF          ; a ON si indicado parámetro /C
  2614. param_h        DB    OFF          ; a ON si indicado parámetro /? o /H
  2615. param_m        DB    OFF          ; a ON si indicado parámetro /M
  2616. param_i        DW    0            ; <> 0 si indicado parámetro /I=
  2617. param_f        DW    1            ; nº de FATs (1-2): parámetro /F=
  2618.  
  2619. tdisco         DW    ?            ; tamaño de disco (Kb)
  2620. ultclus        DW    ?            ; número más alto de cluster
  2621. tamcluster     DW    ?            ; tamaño de cluster (bytes)
  2622. sdir           DW    ?            ; sectores para directorio raiz
  2623. xms_kb         DW    0            ; Kb de memoria XMS libres
  2624. ems_kb         DW    0            ; Kb de memoria EMS libres
  2625. con_kb         DW    0            ; Kb de memoria convencional libres
  2626.  
  2627. sector_cero    LABEL BYTE
  2628.                JMP   SHORT botar
  2629.                NOP
  2630.                DB    "TDSK 2.1"   ; identificación del sistema
  2631. tsect          DW    512          ; tamaño de sector por defecto
  2632. tcluster       DB    ?            ; sectores por cluster
  2633.                DW    1            ; sectores reservados
  2634. nfats          DB    ?            ; número de FAT's
  2635. tdir           DW    ?            ; número de entradas al dir. raiz
  2636. numsect        DW    ?            ; nº sectores del disco (<=32Mb)
  2637.                DB    media        ; descriptor de medio
  2638. sfat           DW    ?            ; sectores por FAT
  2639.                DW    1, 1         ; sectores por pista / cabezas
  2640.                DD    0            ; sectores ocultos
  2641.                DD    0            ; nº total de sectores (si > 32Mb)
  2642.                DB    7 DUP (0)    ; 7 bytes reservados
  2643. botar:         DB    0EAh         ; código de JMP FAR...
  2644.                DW    0,0FFFFh     ; ...FFFF:0000 (programa BOOT)
  2645.                DB    "(c)1993 CiriSOFT"; resto de primeros 64 bytes
  2646.                DB    ". Grupo Universi"
  2647.                DB    "tario de Informá"
  2648.                DB    "tica (GUI) - Val"
  2649.                DB    "ladolid (España)"; resto de primeros 128 bytes
  2650.  
  2651. dir_raiz       DB    "TURBODSK   "; Directorio raiz: primera entrada
  2652.                DB    8            ; etiqueta de volúmen
  2653.                DB    10 DUP (0)   ; reservado
  2654.                DW    ?            ; hora (inicializado al formatear)
  2655.                DW    ?            ; fecha
  2656.                DW    0,0,0        ; últimos bytes (hasta 32)
  2657.  
  2658. ; ------------ Areas de datos para información del disco virtual
  2659.  
  2660.                ; --- Código telefónico de países de habla
  2661.                ;     hispana (mucha o poca).
  2662.  
  2663. paises_sp      DW    54                ; Argentina
  2664.                DW    591               ; Bolivia
  2665.                DW    57                ; Colombia
  2666.                DW    506               ; Costa Rica
  2667.                DW    56                ; Chile
  2668.                DW    593               ; Ecuador
  2669.                DW    503               ; El Salvador
  2670.                DW    34                ; España
  2671.                DW    63                ; Filipinas
  2672.                DW    502               ; Guatemala
  2673.                DW    504               ; Honduras
  2674.                DW    212               ; Marruecos
  2675.                DW    52                ; México
  2676.                DW    505               ; Nicaragua
  2677.                DW    507               ; Panamá
  2678.                DW    595               ; Paraguay
  2679.                DW    51                ; Perú
  2680.                DW    80                ; Puerto Rico
  2681.                DW    508               ; República Dominicana
  2682.                DW    598               ; Uruguay
  2683.                DW    58                ; Venezuela
  2684.                DW    3         ; código genérico COUNTRY.SYS para toda
  2685.                                ; latinoamérica (hasta el DOS 5.0)
  2686. numpaises_sp   EQU   ($-OFFSET paises_sp)/2
  2687.  
  2688. ; ------------ Mensaje de no formateado
  2689.  
  2690.                ; --- en español
  2691.  
  2692. info_ins       DB 10,1,10,"TURBODSK 2.1 - Unidad "
  2693. inf_unidad1    LABEL BYTE
  2694.                DB    "D: sin formatear.",10,1,14,0
  2695.  
  2696.                ; --- en inglés
  2697.  
  2698. info_ins_ex    DB 10,1,10,"TURBODSK 2.1 - Drive "
  2699. inf_unidad1_   LABEL BYTE
  2700.                DB    "D: unformatted.",10,1,14,0
  2701.  
  2702. ; ------------ Cuadro de información
  2703.  
  2704. colA EQU 11+1*16  ; color del recuadro y los mensajes
  2705. colB EQU 15+1*16  ; color de los parámetros de operación del disco
  2706. colC EQU 15+0*16  ; color de lo que rodea a la ventana
  2707. colD EQU 10+1*16  ; color de «TURBODSK»
  2708.  
  2709.                ; --- en español
  2710.  
  2711. info_txt LABEL BYTE
  2712. DB 10,2,12,3,1,colA,"┌",2,26,"─┬",2,26,"─┐",1,colC
  2713. DB 10,2,12,3,1,colA,"│ ",1,colD,"TURBODSK 2.1",1,colA
  2714. DB " - Unidad ",1,colB
  2715. inf_unidad2 LABEL BYTE
  2716. DB "D:",1,colA," │ Tamaño de sector:",1,colB," "
  2717. inf_tsect EQU $
  2718. DB "00000  ",1,colA,"│",1,colC,10,2,12,3
  2719. DB 1,colA,"├",2,26,"─┤ Nº entradas raiz:",1,colB," "
  2720. inf_tdir EQU $
  2721. DB "00000  ",1,colA,"│",1,colC,10
  2722. DB 2,12,3,1,colA,"│ Tamaño:  ",1,colB," "
  2723. inf_tdisco EQU $
  2724. DB "00000 Kbytes   ",1,colA,"│ Sectores/cluster:",1,colB," "
  2725. inf_tcluster EQU $
  2726. DB "00000  ",1,colA,"│",1,colC,10
  2727. DB 2,12,3,1,colA,"│ Memoria:  ",1,colB
  2728. inf_mem EQU $
  2729. DB "Convencional   ",1,colA,"│",1,colB," "
  2730. inf_nclusters EQU $
  2731. DB "00000",1,colA," clusters (",1,colB,"FAT"
  2732. inf_tfat EQU $
  2733. DB "12",1,colA,")   ",1,colA,"│",1,colC,10,2,12,3
  2734. DB 1,colA,"└",2,26,"─┴",2,26,"─┘",1,colC,10,0
  2735.  
  2736. inf_mem_xms DB "Extendida XMS"
  2737. inf_mem_ems DB "Expandida EMS"
  2738. inf_mem_sup DB "   Superior  "
  2739. inf_mem_lon EQU $-OFFSET inf_mem_sup
  2740.  
  2741.                ; --- en inglés
  2742.  
  2743. info_txt_ex LABEL BYTE
  2744. DB 10,2,12,3,1,colA,"┌",2,26,"─┬",2,26,"─┐",1,colC
  2745. DB 10,2,12,3,1,colA,"│ ",1,colD,"TURBODSK 2.1",1,colA
  2746. DB " - Drive ",1,colB
  2747. inf_unidad2_ LABEL BYTE
  2748. DB "D:",1,colA,"  │ Sector size:",2,5," ",1,colB," "
  2749. inf_tsect_ EQU $
  2750. DB "00000  ",1,colA,"│",1,colC,10,2,12,3
  2751. DB 1,colA,"├",2,26,"─┤ Root entries:",2,4," ",1,colB," "
  2752. inf_tdir_ EQU $
  2753. DB "00000  ",1,colA,"│",1,colC,10
  2754. DB 2,12,3,1,colA,"│ Size:",2,4," ",1,colB," "
  2755. inf_tdisco_ EQU $
  2756. DB "00000 Kbytes   ",1,colA,"│ Sectors/cluster: ",1,colB," "
  2757. inf_tcluster_ EQU $
  2758. DB "00000  ",1,colA,"│",1,colC,10
  2759. DB 2,12,3,1,colA,"│ Memory:   ",1,colB
  2760. inf_mem_ EQU $
  2761. DB "Conventional   ",1,colA,"│",1,colB," "
  2762. inf_nclusters_ EQU $
  2763. DB "00000",1,colA," clusters (",1,colB,"FAT"
  2764. inf_tfat_ EQU $
  2765. DB "12",1,colA,")   ",1,colA,"│",1,colC,10,2,12,3
  2766. DB 1,colA,"└",2,26,"─┴",2,26,"─┘",1,colC,10,0
  2767.  
  2768. inf_mem_xms_ex DB "Extended XMS "
  2769. inf_mem_ems_ex DB "Expanded EMS "
  2770. inf_mem_sup_ex DB "    Upper    "
  2771.  
  2772. ; ------------ Errores «leves»
  2773.  
  2774. ERROR0         EQU   1
  2775. ERROR1         EQU   2
  2776. ERROR2         EQU   4
  2777. ERROR3         EQU   8         ; TURBODSK es muy flexible y se instala
  2778. ERROR4         EQU   16        ; casi de cualquier forma, aunque a
  2779. ERROR5         EQU   32        ; veces no se reserve memoria y sea
  2780. ERROR6         EQU   64        ; necesario volver a ejecutarlo después
  2781. ERROR7         EQU   128       ; desde el DOS para «formatearlo».
  2782. ERROR8         EQU   256
  2783. ERROR9         EQU   512
  2784. ERROR10        EQU   1024
  2785. ERROR11        EQU   2048
  2786. ERROR12        EQU   4096
  2787. ERROR13        EQU   8192
  2788. ERROR14        EQU   16384
  2789. ERROR15        EQU   32768
  2790.  
  2791. lista_err      DW    0    ; palabra que indica los mensajes a imprimir
  2792.  
  2793. mens_cabec     DB    2,8,3,0
  2794.  
  2795. tabla_mens     DW    m0,m1,m2,m3,m4,m5,m6,m7
  2796.                DW    m8,m9,m10,m11,m12,m13,m14,m15
  2797.  
  2798. tabla_mens_ex  DW    m0_ex,m1_ex,m2_ex,m3_ex,m4_ex,m5_ex,m6_ex,m7_ex
  2799.                DW    m8_ex,m9_ex,m10_ex,m11_ex,m12_ex,m13_ex,m14_ex
  2800.                DW    m15_ex
  2801.  
  2802. cab_adv_txt    DB    10,2,8,3,1,12
  2803.                DB    "Advertencias y/o errores de TURBODSK:",2,27," "
  2804.                DB    10,1,10,0
  2805.  
  2806. cab_adv_ex_txt DB    10,2,8,3,1,12,"Warnings and errors of TURBODSK:"
  2807.                DB    2,32," ",10,1,10,0
  2808.  
  2809.                ; --- Mensajes en español
  2810.  
  2811. m0 LABEL BYTE
  2812. DB "- Error de sintaxis o parámetro fuera de rango.  No se define el"
  2813. DB 10,2,8,3
  2814. DB "  disco virtual ahora o no se modifica el que estaba definido.  "
  2815. DB 10,0
  2816.  
  2817. m1 LABEL BYTE
  2818. DB "- El parámetro /C o la letra de unidad sólo han de emplearse"
  2819. DB 2,4," ",10,2,8,3
  2820. DB "  desde la línea de comandos o el AUTOEXEC (les ignoraré)."
  2821. DB 2,6," ",10,0
  2822.  
  2823. m2 LABEL BYTE
  2824. DB "- Para poder emplear memoria expandida hay que incluir la opción"
  2825. DB 10,2,8,3
  2826. DB "  /A en CONFIG.SYS, con objeto de dejar espacio para las rutinas"
  2827. DB 10,2,8,3
  2828. DB "  de control EMS: la memoria ocupada crecerá de 432 a 608 bytes."
  2829. DB 10,0
  2830.  
  2831. m3 LABEL BYTE
  2832. DB "- El tamaño de sector es mayor que el definido en cualquier otro"
  2833. DB 10,2,8,3
  2834. DB "  controlador de dispositivo: indíquese ese tamaño en CONFIG.SYS"
  2835. DB 10,2,8,3
  2836. DB "  para que el DOS ajuste sus buffers (¡más consumo de memoria!)."
  2837. DB 10,0
  2838.  
  2839. m4 LABEL BYTE
  2840. DB "- La cantidad de memoria solicitada no existe, se ha rebajado.  "
  2841. DB 10,0
  2842.  
  2843. m5 LABEL BYTE
  2844. DB "- No hay memoria XMS/EMS disponible: no la reservo; ejecute TDSK"
  2845. DB 10,2,8,3
  2846. DB "  de nuevo desde el DOS para utilizar memoria convencional."
  2847. DB 2,5," ",10,0
  2848.  
  2849. m6 LABEL BYTE
  2850. DB "- No existe memoria XMS: pruebe a indicar EMS en su lugar (/A)  "
  2851. DB 10,0
  2852.  
  2853. m7 LABEL BYTE
  2854. DB "- No existe memoria EMS: pruebe a indicar XMS en su lugar (/E)  "
  2855. DB 10,0
  2856.  
  2857. m8 LABEL BYTE
  2858. DB "- Fallo del controlador XMS: imposible usar memoria extendida.  "
  2859. DB 10,0
  2860.  
  2861. m9 LABEL BYTE
  2862. DB "- Fallo del controlador EMS: imposible usar memoria expandida.  "
  2863. DB 10,0
  2864.  
  2865. m10 LABEL BYTE
  2866. DB "- No existe suficiente memoria convencional para TURBODSK."
  2867. DB 2,6," ",10,0
  2868.  
  2869. m11 LABEL BYTE
  2870. DB "- Tamaño de sector incorrecto: lo establezco por defecto."
  2871. DB 2,7," ",10,0
  2872.  
  2873. m12 LABEL BYTE
  2874. DB "- Número de entradas incorrecto: lo establezco por defecto."
  2875. DB 2,5," ",10,0
  2876.  
  2877. m13 LABEL BYTE
  2878. DB "- Tamaño de cluster incorrecto: lo establezco por defecto."
  2879. DB 2,6," ",10,0
  2880.  
  2881. m14 LABEL BYTE
  2882. DB "- FATAL: fallo al liberar la memoria que ocupaba el disco."
  2883. DB 2,6," ",10,0
  2884.  
  2885. m15 LABEL BYTE
  2886. DB "- Para discos de más de 32 Mb, hace falta un tamaño de sector de"
  2887. DB 10,2,8,3,"  al menos 1024 bytes.",2,42," ",10,0
  2888.  
  2889.                ; --- Mensajes en inglés
  2890.  
  2891. m0_ex LABEL BYTE
  2892. DB "- Syntax error and/or parameter out of range. The Ramdisk is not"
  2893. DB 10,2,8,3
  2894. DB "  defined now or the previous one is not modified.",2,14," ",10,0
  2895.  
  2896. m1_ex LABEL BYTE
  2897. DB "- The /C parameter and the driver letter only can be used when  "
  2898. DB 10,2,8,3
  2899. DB "  executing TURBODSK in command line or AUTOEXEC (now, ignored)."
  2900. DB 10,0
  2901.  
  2902. m2_ex LABEL BYTE
  2903. DB "- In order to use expanded memory you must include the /A option"
  2904. DB 10,2,8,3
  2905. DB "  in CONFIG.SYS, needed to reserve too space for the EMS support"
  2906. DB 10,2,8,3
  2907. DB "  routines: the memory used will increase from 432 to 608 bytes."
  2908. DB 10,0
  2909.  
  2910. m3_ex LABEL BYTE
  2911. DB "- Sector size is greater than any other defined  by  any  device"
  2912. DB 10,2,8,3
  2913. DB "  driver loaded: you must indicate the sector size in CONFIG.SYS"
  2914. DB 10,2,8,3
  2915. DB "  because DOS need adjust buffers length (more memory spent!).  "
  2916. DB 10,0
  2917.  
  2918. m4_ex LABEL BYTE
  2919. DB "- The amount of memory requested does not exist: size reduced.  "
  2920. DB 10,0
  2921.  
  2922. m5_ex LABEL BYTE
  2923. DB "- There is not XMS/EMS memory available: execute TDSK again from"
  2924. DB 10,2,8,3
  2925. DB "  DOS command line or AUTOEXEC and use conventional memory."
  2926. DB 2,5," ",10,0
  2927.  
  2928. m6_ex LABEL BYTE
  2929. DB "- There is not XMS memory available: try to request EMS (/A).   "
  2930. DB 10,0
  2931.  
  2932. m7_ex LABEL BYTE
  2933. DB "- There is not EMS memory available: try to request XMS (/E).   "
  2934. DB 10,0
  2935.  
  2936. m8_ex LABEL BYTE
  2937. DB "- XMS controller failure: imposible to use extended memory."
  2938. DB 2,5," ",10,0
  2939.  
  2940. m9_ex LABEL BYTE
  2941. DB "- EMS controller failure: imposible to use expanded memory."
  2942. DB 2,5," ",10,0
  2943.  
  2944. m10_ex LABEL BYTE
  2945. DB "- There is not sufficient conventional memory for TURBODSK."
  2946. DB 2,5," ",10,0
  2947.  
  2948. m11_ex LABEL BYTE
  2949. DB "- Incorrect sector size indicated: default values assumed."
  2950. DB 2,6," ",10,0
  2951.  
  2952. m12_ex LABEL BYTE
  2953. DB "- Incorrect number of root entries: default value assumed."
  2954. DB 2,6," ",10,0
  2955.  
  2956. m13_ex LABEL BYTE
  2957. DB "- Incorrect cluster size indicated: default value assumed."
  2958. DB 2,6," ",10,0
  2959.  
  2960. m14_ex LABEL BYTE
  2961. DB "- FATAL: imposible to free memory alocated by TURBODSK."
  2962. DB 2,9," ",10,0
  2963.  
  2964. m15_ex LABEL BYTE
  2965. DB "- In drives over 32 Mb, sector size must be at least 1024 bytes."
  2966. DB 10,0
  2967.  
  2968. ; ------------ Errores «graves» (se imprime sólo el más importante)
  2969.  
  2970. err_grave      DW    0   ; tipo de error grave a imprimir
  2971.  
  2972. err_grave_gen  DB    10,1,10,"TURBODSK 2.1",10,1,12,0
  2973.  
  2974.                ; --- En español
  2975.  
  2976. e0  DB "  - Este disco virtual requiere DOS 2.0 o superior.",10,0
  2977.  
  2978. e1  DB "  - Instale primero TURBODSK desde CONFIG.SYS (con DEVICE)."
  2979.     DB 10,"  - Puede solicitar ayuda con TDSK /?",10,0
  2980.  
  2981. e2  DB "  - La unidad indicada no es un dispositivo TURBODSK 2.1",10,0
  2982.  
  2983. e3  DB "  - No pueden modificarse las características de operación de"
  2984.     DB 10
  2985.     DB "    TURBODSK dentro de WINDOWS. Configúrelo con anterioridad."
  2986.     DB 10,0
  2987.                ; --- En inglés
  2988.  
  2989. e0_ex  DB "  - This Ram Disk needs at least DOS 2.0 or above.",10,0
  2990.  
  2991. e1_ex  DB "  - You must install before TURBODSK from CONFIG.SYS "
  2992.        DB "(using DEVICE).",10
  2993.        DB "  - Help is available with TDSK /?",10,0
  2994.  
  2995. e2_ex  DB "  - Drive letter indicated does not is a TURBODSK 2.1 "
  2996.        DB "device.",10,0
  2997.  
  2998. e3_ex  DB "  - Operational characteristics of disk can not be "
  2999.        DB "altered inside",10,2,4," a WINDOWS session. You must "
  3000.        DB "configure TURBODSK before.",10,0
  3001.  
  3002. ; ------------ Ayuda
  3003.  
  3004. colorA   EQU 15+4*16+128  ; color de «TURBODSK»
  3005. colorAm  EQU 14+1*16      ; color del marco de fondo de «TURBODSK»
  3006. colorB   EQU 13+1*16      ; color de la fecha
  3007. colorC   EQU 10+1*16      ; color de sintaxis y parámetros
  3008. colorD   EQU 15+1*16      ; color principal del texto
  3009. colorDm  EQU 11+1*16      ; color del marco de fondo
  3010. colorDmx EQU 11+0*16      ; color de la esquina del marco
  3011. colorE   EQU 11+1*16      ; color del nombre del autor
  3012. colorF   EQU 14+1*16      ; color para llamar la atención
  3013. colorG   EQU 12+1*16      ; color para la dirección de mail
  3014. colorH   EQU  9+1*16      ; color para mensaje de dominio público
  3015.  
  3016.                ; --- En español
  3017.  
  3018. ayuda_txt LABEL BYTE
  3019. DB 10,3,1,colorDm,"  ",1,colorA," TURBODSK 2.1 ",1,colorAm,"▄"
  3020. DB    1,colorB,2,52," 31/1/93 ",1,colorDmx,"▄",10
  3021. DB 3,1,colorE,"   ",1,colorAm,2,14,"▀",1,colorE
  3022. DB    "  (c) 1993 Ciriaco García de Celis. ",1,colorG
  3023. DB    "(Mail: gui@cpd.uva.es). ",1,colorDm,"█",10
  3024. DB 3,1,colorE," (c) Grupo Universitario de Informática. "
  3025. DB    "Apartado 6062, Valladolid (España). ",1,colorDm,"█",10
  3026. DB 3,1,colorH,2,18," ","* * *  Programa de Dominio Público  * * *"
  3027. DB    2,18," ",1,colorDm,"█",10
  3028. DB 3,1,colorD,"   Bienvenido al disco virtual ",1,colorF,"más rápido"
  3029. DB    1,colorD,", con soporte de memoria EMS, XMS y ",1,colorDm,"█",10
  3030. DB 3,1,colorD," convencional; redimensionable, fácil de usar. En DOS "
  3031. DB    "5 ocupa 432-608 bytes. ",1,colorDm,"█",10
  3032. DB 3,1,colorC,2,77," ",1,colorDm,"█",10
  3033. DB 3,1,colorC," DEVICE=TDSK.EXE [tamaño [tsector "
  3034. DB    "[nfich [scluster]]]] [/E] [/A|X] [/C] [/M] ",1,colorDm,"█",10
  3035. DB 3,1,colorC,2,77," ",1,colorDm,"█",10
  3036. DB 3,1,colorD," ",1,colorF,"■",1,colorD," El tamaño debe de estar en "
  3037. DB    "el rango 8 - 65534 Kb; son válidos sectores de ",1,colorDm
  3038. DB    "█",10
  3039. DB 3,1,colorD," 32 a 2048 bytes (en potencias de dos, aunque algún "
  3040. DB    "sistema sólo los soporta ",1,colorDm,"█",10
  3041. DB 3,1,colorD," de 128 a 512). El número de ficheros del directorio "
  3042. DB    "raiz debe estar entre 1 ",1,colorDm,"█",10
  3043. DB 3,1,colorD," y 65534 y el de sectores por cluster entre 1 y 255 ("
  3044. DB    "en algún sistema han de ",1,colorDm,"█",10
  3045. DB 3,1,colorD," ser potencia de dos). Según el tamaño se ajustará "
  3046. DB    "lo demás automáticamente. ",1,colorDm,"█",10
  3047. DB 3,1,colorD," ",1,colorF,"■",1,colorD," Se puede indicar ",1,colorC
  3048. DB    "/E",1,colorD," para emplear memoria extendida XMS, y ",1,colorC
  3049. DB    "/A",1,colorD," o ",1,colorC,"/X",1,colorD," para la ",1,colorDm
  3050. DB    "█",10
  3051. DB 3,1,colorD," expandida EMS; aunque por defecto, TURBODSK utilizará"
  3052. DB    " automáticamente estas ",1,colorDm,"█",10
  3053. DB 3,1,colorD," memorias si puede. Con la opción ",1,colorC,"/C"
  3054. DB    1,colorD," se pide el uso de memoria convencional. ",1,colorDm
  3055. DB    "█",10
  3056. DB 3,1,colorD,32,1,colorF,"■",1,colorD," Tras ser instalado, se puede"
  3057. DB    " ejecutar desde el DOS para cambiar el tamaño ",1,colorDm
  3058. DB    "█",10
  3059. DB 3,1,colorD," del disco (perdiéndose los datos almacenados):  con "
  3060. DB    "un tamaño 0 se anula el ",1,colorDm,"█",10
  3061. DB 3,1,colorD," disco por completo, liberándose la memoria. "
  3062. DB    "Utilizando memoria convencional ",1,colorDm,"█",10
  3063. DB 3,1,colorD," es ",1,colorF,"MUY",1,colorD," conveniente anular el "
  3064. DB    "disco previo antes de modificar su tamaño. Con ",1,colorDm
  3065. DB    "█",10
  3066. DB 3,1,colorD," más de un disco presente se pueden distinguir "
  3067. DB    "indicando la letra de unidad. ",1,colorDm,"█",10
  3068. DB 3,1,1*16,"▄",1,colorDm,2,76,"▄█",10,0
  3069.  
  3070.                ; --- En inglés
  3071.  
  3072. ayuda_ex_txt LABEL BYTE
  3073. DB 10,3,1,colorDm,"  ",1,colorA," TURBODSK 2.1 ",1,colorAm,"▄"
  3074. DB    1,colorB,2,52," 1/31/93 ",1,colorDmx,"▄",10
  3075. DB 3,1,colorE,"   ",1,colorAm,2,14,"▀",1,colorE
  3076. DB    "  (c) 1993 Ciriaco Garcia de Celis. ",1,colorG
  3077. DB    "(Mail: gui@cpd.uva.es). ",1,colorDm,"█",10
  3078. DB 3,1,colorE,"  (c) Grupo Universitario de Informática. "
  3079. DB    "Apartado 6062, Valladolid (Spain). ",1,colorDm,"█",10
  3080. DB 3,1,colorC,2,77," ",1,colorDm,"█",10
  3081. DB 3,1,colorD,"   Welcome to the ",1,colorF,"faster",1,colorD
  3082. DB    " RAM disk!,  which includes support of both EMS, XMS "
  3083. DB    1,colorDm,"█",10
  3084. DB 3,1,colorD," and conventional memory.  Full resizeable,  easy to "
  3085. DB    "use like DOS RAM disks, ",1,colorDm,"█",10
  3086. DB 3,1,colorD," in DOS 5.0 it takes only about 432-608 bytes. "
  3087. DB    1,colorH,"This program is freeware!.",2,4," ",1,colorDm,"█",10
  3088. DB 3,1,colorC,2,77," ",1,colorDm,"█",10
  3089. DB 3,1,colorC," DEVICE=TDSK.EXE [size [s_sector [files [s_cluster]]]]"
  3090. DB    " [/E] [/A|X] [/C] [/M] ",1,colorDm,"█",10
  3091. DB 3,1,colorC,2,77," ",1,colorDm,"█",10
  3092. DB 3,1,colorD," ",1,colorF,"■",1,colorD," Size must be in the range "
  3093. DB    "8 - 65534 Kb; are valid sectors from 32 to 2048 ",1,colorDm
  3094. DB    "█",10
  3095. DB 3,1,colorD," bytes (in power of 2), though some DOS versions only "
  3096. DB    "support 128, 256 & 512 ",1,colorDm,"█",10
  3097. DB 3,1,colorD," bytes. Files of root may be 1 to 65534 and sectors "
  3098. DB    "by cluster can vary from ",1,colorDm,"█",10
  3099. DB 3,1,colorD," 1 to 255 (some systems need a power of 2). Only the "
  3100. DB    "size is necessary.",2,6," ",1,colorDm,"█",10
  3101. DB 3,1,colorD," ",1,colorF,"■",1,colorC," /E",1,colorD," force the "
  3102. DB    "use of XMS memory, ",1,colorC,"/A",1,colorD," and ",1,colorC
  3103. DB    "/X",1,colorD," indicates the use of EMS memory ",1,colorDm
  3104. DB    "█",10
  3105. DB 3,1,colorD," and ",1,colorC,"/C",1,colorD," the conventional. By "
  3106. DB    "default, TURBODSK try to use XMS or EMS memory. ",1,colorDm
  3107. DB    "█",10
  3108. DB 3,1,colorD," ",1,colorF,"■",1,colorD," After been installed in "
  3109. DB    "CONFIG.SYS, TURBODSK must be executed in AUTOEXEC ",1,colorDm
  3110. DB    "█",10
  3111. DB 3,1,colorD," or command line in order to vary the disk size (the "
  3112. DB    "amount of memory used); ",1,colorDm,"█",10
  3113. DB 3,1,colorD," this operation erase the disk contents.  A size 0 "
  3114. DB    "can be used to complitely ",1,colorDm,"█",10
  3115. DB 3,1,colorD," anulation of the disk freezen the memory: when using "
  3116. DB    "conventional memory it ",1,colorDm,"█",10
  3117. DB 3,1,colorD," is useful to annulate the disk ",1,colorF,"BEFORE"
  3118. DB    1,colorD," resizing. When more than one TURBODSK ",1,colorDm
  3119. DB    "█",10
  3120. DB 3,1,colorD," is installed, they can be identified using in "
  3121. DB    "adition the drive letter.",2,5," ",1,colorDm,"█",10
  3122. DB 3,1,1*16,"▄",1,colorDm,2,76,"▄█",10,0
  3123.  
  3124. tam_a_trabajo  EQU   2048              ; tamaño del mayor sector
  3125.                                        ; soportado por TURBODSK
  3126. area_trabajo   EQU   $
  3127.                DB    tam_a_trabajo DUP (?)
  3128.  
  3129. _PRINCIPAL     ENDS
  3130.  
  3131. tam_pila       EQU   1024              ; 1 Kb de pila es suficiente
  3132.  
  3133. _PILA          SEGMENT STACK 'STACK'
  3134.                DB    tam_pila DUP (?)
  3135. _PILA          ENDS
  3136.  
  3137.                END   main
  3138.